merged opnnebula api changes
This commit is contained in:
		
				commit
				
					
						8980f6b2fc
					
				
			
		
					 19 changed files with 458 additions and 888 deletions
				
			
		| 
						 | 
				
			
			@ -12,6 +12,8 @@ import debug_toolbar
 | 
			
		|||
 | 
			
		||||
urlpatterns = [   url(r'^index.html$', LandingView.as_view()),
 | 
			
		||||
                  url(r'^hosting/', include('hosting.urls', namespace="hosting")),
 | 
			
		||||
                  url(r'^open_api/', include('opennebula_api.urls',
 | 
			
		||||
                      namespace='opennebula_api')),
 | 
			
		||||
                  url(r'^railshosting/', RailsHostingView.as_view(), name="rails.hosting"),
 | 
			
		||||
                  url(r'^nodehosting/', NodeJSHostingView.as_view(), name="node.hosting"),
 | 
			
		||||
                  url(r'^djangohosting/', DjangoHostingView.as_view(), name="django.hosting"),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,99 +4,8 @@ from django.core.urlresolvers import reverse
 | 
			
		|||
 | 
			
		||||
from utils.mailer import BaseEmail
 | 
			
		||||
 | 
			
		||||
from .forms import HostingOrderAdminForm
 | 
			
		||||
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, \
 | 
			
		||||
                    ManageVM, HostingBill
 | 
			
		||||
from .opennebula_functions import HostingManageVMAdmin
 | 
			
		||||
from .models import HostingOrder, HostingBill
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HostingOrderAdmin(admin.ModelAdmin):
 | 
			
		||||
    # fields = ('slug', 'imdb_link', 'start', 'finish', 'added_by')
 | 
			
		||||
    list_display = ('id', 'created_at', 'plan', 'user')
 | 
			
		||||
    search_fields = ['vm_plan__id', 'customer__user__email']
 | 
			
		||||
 | 
			
		||||
    def save_model(self, request, obj, form, change):
 | 
			
		||||
        if not change:
 | 
			
		||||
            customer = form.cleaned_data.get('customer')
 | 
			
		||||
 | 
			
		||||
            # Get and set billing address from the lastest charged order
 | 
			
		||||
            last_order = HostingOrder.objects.filter(customer=customer).latest('id')
 | 
			
		||||
            billing_address = last_order.billing_address
 | 
			
		||||
            obj.billing_address = billing_address
 | 
			
		||||
 | 
			
		||||
            charge = form.cleaned_data.get('charge')
 | 
			
		||||
            # Associate an order with a stripe payment
 | 
			
		||||
            obj.set_stripe_charge(charge)
 | 
			
		||||
 | 
			
		||||
            # If the Stripe payment was successed, set order status approved
 | 
			
		||||
            obj.set_approved()
 | 
			
		||||
 | 
			
		||||
            # Assigning permissions
 | 
			
		||||
            obj.assign_permissions(customer.user)
 | 
			
		||||
 | 
			
		||||
            context = {
 | 
			
		||||
                'order': obj,
 | 
			
		||||
                'vm': obj.vm_plan,
 | 
			
		||||
                'base_url': "{0}://{1}".format(request.scheme, request.get_host())
 | 
			
		||||
            }
 | 
			
		||||
            email_data = {
 | 
			
		||||
                'subject': 'Your VM plan has been charged',
 | 
			
		||||
                'to': obj.customer.user.email,
 | 
			
		||||
                'context': context,
 | 
			
		||||
                'template_name': 'vm_charged',
 | 
			
		||||
                'template_path': 'hosting/emails/'
 | 
			
		||||
            }
 | 
			
		||||
            email = BaseEmail(**email_data)
 | 
			
		||||
            email.send()
 | 
			
		||||
 | 
			
		||||
        obj.save()
 | 
			
		||||
        return obj
 | 
			
		||||
 | 
			
		||||
    def get_form(self, request, obj=None, **kwargs):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            kwargs['form'] = HostingOrderAdminForm
 | 
			
		||||
        return super(HostingOrderAdmin, self).get_form(request, obj, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def user(self, obj):
 | 
			
		||||
        email = obj.customer.user.email
 | 
			
		||||
        user_url = reverse("admin:membership_customuser_change", args=[obj.customer.user.id])
 | 
			
		||||
        return format_html("<a href='{url}'>{email}</a>", url=user_url, email=email)
 | 
			
		||||
 | 
			
		||||
    def plan(self, obj):
 | 
			
		||||
        vm_name = obj.vm_plan.name
 | 
			
		||||
        vm_url = reverse("admin:hosting_virtualmachineplan_change", args=[obj.vm_plan.id])
 | 
			
		||||
        return format_html("<a href='{url}'>{vm_name}</a>", url=vm_url, vm_name=vm_name)
 | 
			
		||||
 | 
			
		||||
    plan.short_description = "Virtual Machine Plan"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VirtualMachinePlanAdmin(admin.ModelAdmin):
 | 
			
		||||
    list_display = ('name', 'id', 'email')
 | 
			
		||||
 | 
			
		||||
    def email(self, obj):
 | 
			
		||||
        return obj.hosting_orders.latest('id').customer.user.email
 | 
			
		||||
 | 
			
		||||
    def save_model(self, request, obj, form, change):
 | 
			
		||||
        email = self.email(obj)
 | 
			
		||||
        if 'status' in form.changed_data:
 | 
			
		||||
            context = {
 | 
			
		||||
                'vm': obj,
 | 
			
		||||
                'base_url': "{0}://{1}".format(request.scheme, request.get_host())
 | 
			
		||||
            }
 | 
			
		||||
            email_data = {
 | 
			
		||||
                'subject': 'Your VM has been activated',
 | 
			
		||||
                'to': email,
 | 
			
		||||
                'context': context,
 | 
			
		||||
                'template_name': 'vm_status_changed',
 | 
			
		||||
                'template_path': 'hosting/emails/'
 | 
			
		||||
            }
 | 
			
		||||
            email = BaseEmail(**email_data)
 | 
			
		||||
            email.send()
 | 
			
		||||
        obj.save()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
admin.site.register(HostingOrder, HostingOrderAdmin)
 | 
			
		||||
admin.site.register(VirtualMachineType)
 | 
			
		||||
admin.site.register(VirtualMachinePlan, VirtualMachinePlanAdmin)
 | 
			
		||||
admin.site.register(ManageVM, HostingManageVMAdmin)
 | 
			
		||||
admin.site.register(HostingOrder)
 | 
			
		||||
admin.site.register(HostingBill)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,39 +7,7 @@ from django.contrib.auth import authenticate
 | 
			
		|||
 | 
			
		||||
from utils.stripe_utils import StripeUtils
 | 
			
		||||
 | 
			
		||||
from .models import HostingOrder, VirtualMachinePlan, UserHostingKey
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HostingOrderAdminForm(forms.ModelForm):
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = HostingOrder
 | 
			
		||||
        fields = ['vm_plan', 'customer']
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        customer = self.cleaned_data.get('customer')
 | 
			
		||||
        vm_plan = self.cleaned_data.get('vm_plan')
 | 
			
		||||
 | 
			
		||||
        if vm_plan.status == VirtualMachinePlan.CANCELED_STATUS:
 | 
			
		||||
            raise forms.ValidationError("""You can't make a charge over
 | 
			
		||||
                                         a canceled virtual machine plan""")
 | 
			
		||||
 | 
			
		||||
        if not customer:
 | 
			
		||||
            raise forms.ValidationError("""You need select a costumer""")
 | 
			
		||||
 | 
			
		||||
        # Make a charge to the customer
 | 
			
		||||
        stripe_utils = StripeUtils()
 | 
			
		||||
        charge_response = stripe_utils.make_charge(customer=customer.stripe_id,
 | 
			
		||||
                                                   amount=vm_plan.price)
 | 
			
		||||
        charge = charge_response.get('response_object')
 | 
			
		||||
        if not charge:
 | 
			
		||||
            raise forms.ValidationError(charge_response.get('error'))
 | 
			
		||||
 | 
			
		||||
        self.cleaned_data.update({
 | 
			
		||||
            'charge': charge
 | 
			
		||||
        })
 | 
			
		||||
        return self.cleaned_data
 | 
			
		||||
 | 
			
		||||
from .models import HostingOrder, UserHostingKey
 | 
			
		||||
 | 
			
		||||
class HostingUserLoginForm(forms.Form):
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								hosting/migrations/0038_auto_20170512_1006.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								hosting/migrations/0038_auto_20170512_1006.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.9.4 on 2017-05-12 10:06
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('hosting', '0037_merge'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.RemoveField(
 | 
			
		||||
            model_name='virtualmachineplan',
 | 
			
		||||
            name='vm_type',
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.RemoveField(
 | 
			
		||||
            model_name='hostingorder',
 | 
			
		||||
            name='vm_plan',
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='hostingorder',
 | 
			
		||||
            name='vm_id',
 | 
			
		||||
            field=models.IntegerField(default=0),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.DeleteModel(
 | 
			
		||||
            name='VirtualMachinePlan',
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.DeleteModel(
 | 
			
		||||
            name='VirtualMachineType',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										21
									
								
								hosting/migrations/0039_hostingorder_price.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								hosting/migrations/0039_hostingorder_price.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.9.4 on 2017-05-12 16:37
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('hosting', '0038_auto_20170512_1006'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='hostingorder',
 | 
			
		||||
            name='price',
 | 
			
		||||
            field=models.FloatField(default=0),
 | 
			
		||||
            preserve_default=False,
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,35 +1,20 @@
 | 
			
		|||
from django.shortcuts import redirect
 | 
			
		||||
from django.core.urlresolvers import reverse
 | 
			
		||||
from .models import VirtualMachinePlan, VirtualMachineType
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProcessVMSelectionMixin(object):
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
        configuration = request.POST.get('configuration')
 | 
			
		||||
        configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
 | 
			
		||||
        vm_template = request.POST.get('vm_template')
 | 
			
		||||
        vm_type = VirtualMachineType.objects.get(id=vm_template)
 | 
			
		||||
        vm_specs = vm_type.get_specs()
 | 
			
		||||
        #configuration = request.POST.get('configuration')
 | 
			
		||||
        #configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
 | 
			
		||||
        vm_template_id = request.POST.get('vm_template_id')
 | 
			
		||||
        vm_specs.update({
 | 
			
		||||
            'configuration_display': configuration_display,
 | 
			
		||||
            'configuration': configuration,
 | 
			
		||||
            'final_price': vm_type.final_price,
 | 
			
		||||
            'vm_template': vm_template
 | 
			
		||||
            'vm_template_id': vm_template_id
 | 
			
		||||
        })
 | 
			
		||||
        # vm_specs = {
 | 
			
		||||
        #     # 'cores': request.POST.get('cores'),
 | 
			
		||||
        #     # 'memory': request.POST.get('memory'),
 | 
			
		||||
        #     # 'disk_size': request.POST.get('disk_space'),
 | 
			
		||||
        #     # 'hosting_company': request.POST.get('hosting_company'),
 | 
			
		||||
        #     # 'location_code': request.POST.get('location_code'),
 | 
			
		||||
        #     # 'configuration': hosting,
 | 
			
		||||
        #     # 'configuration_detail': configuration_detail,
 | 
			
		||||
        #     'final_price': request.POST.get('final_price')
 | 
			
		||||
        # }
 | 
			
		||||
        request.session['vm_specs'] = vm_specs
 | 
			
		||||
        if not request.user.is_authenticated():
 | 
			
		||||
            request.session['vm_specs'] = vm_specs
 | 
			
		||||
            request.session['next'] = reverse('hosting:payment')
 | 
			
		||||
            return redirect(reverse('hosting:login'))
 | 
			
		||||
        return redirect(reverse('hosting:payment'))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,7 @@
 | 
			
		|||
import os
 | 
			
		||||
import socket
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import oca
 | 
			
		||||
from django.db import models
 | 
			
		||||
| 
						 | 
				
			
			@ -19,252 +21,15 @@ from .managers import VMPlansManager
 | 
			
		|||
from oca.exceptions import OpenNebulaException
 | 
			
		||||
from oca.pool import WrongNameError
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
class VirtualMachineType(models.Model):
 | 
			
		||||
 | 
			
		||||
    description = models.TextField()
 | 
			
		||||
    base_price = models.FloatField()
 | 
			
		||||
    memory_price = models.FloatField()
 | 
			
		||||
    core_price = models.FloatField()
 | 
			
		||||
    disk_size_price = models.FloatField()
 | 
			
		||||
    cores = models.IntegerField()
 | 
			
		||||
    memory = models.IntegerField()
 | 
			
		||||
    disk_size = models.IntegerField()
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return "VM Type %s" % (self.id)
 | 
			
		||||
 | 
			
		||||
    @cached_property
 | 
			
		||||
    def final_price(self):
 | 
			
		||||
        price = self.cores * self.core_price
 | 
			
		||||
        price += self.memory * self.memory_price
 | 
			
		||||
        price += self.disk_size * self.disk_size_price
 | 
			
		||||
        return price
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_serialized_vm_types(cls):
 | 
			
		||||
        return [vm.get_serialized_data()
 | 
			
		||||
                for vm in cls.objects.all()]
 | 
			
		||||
 | 
			
		||||
    def calculate_price(self):
 | 
			
		||||
        price = self.cores * self.core_price
 | 
			
		||||
        price += self.memory * self.memory_price
 | 
			
		||||
        price += self.disk_size * self.disk_size_price
 | 
			
		||||
        # price += self.base_price
 | 
			
		||||
        return price
 | 
			
		||||
 | 
			
		||||
    # @classmethod
 | 
			
		||||
    # def get_price(cls, vm_template):
 | 
			
		||||
    #     return cls.BASE_PRICE * vm_template
 | 
			
		||||
 | 
			
		||||
    def get_specs(self):
 | 
			
		||||
        return {
 | 
			
		||||
            'memory': self.memory,
 | 
			
		||||
            'cores': self.cores,
 | 
			
		||||
            'disk_size': self.disk_size
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    # def calculate_price(self, vm_template):
 | 
			
		||||
    #     price = self.base_price * vm_template
 | 
			
		||||
    #     return price
 | 
			
		||||
 | 
			
		||||
    # def defeault_price(self):
 | 
			
		||||
    #     price = self.base_price
 | 
			
		||||
    #     price += self.core_price
 | 
			
		||||
    #     price += self.memory_price
 | 
			
		||||
    #     price += self.disk_size_price * 10
 | 
			
		||||
    #     return price
 | 
			
		||||
 | 
			
		||||
    def get_serialized_data(self):
 | 
			
		||||
        return {
 | 
			
		||||
            'description': self.description,
 | 
			
		||||
            'core_price': self.core_price,
 | 
			
		||||
            'disk_size_price': self.disk_size_price,
 | 
			
		||||
            'memory_price': self.memory_price,
 | 
			
		||||
            'id': self.id,
 | 
			
		||||
            'final_price': self.final_price,
 | 
			
		||||
            'cores': self.cores,
 | 
			
		||||
            'memory': self.memory,
 | 
			
		||||
            'disk_size': self.disk_size
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_vm_templates(self, user):
 | 
			
		||||
        opennebula_client = OpenNebulaManager(
 | 
			
		||||
            email=user.email,
 | 
			
		||||
            password=user.password,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        templates = opennebula_client.get_vm_templates()
 | 
			
		||||
        for template in templates:
 | 
			
		||||
            print(OpenNebulaManager.parse_vm(template))
 | 
			
		||||
        return templates
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VirtualMachinePlan(AssignPermissionsMixin, models.Model):
 | 
			
		||||
 | 
			
		||||
    PENDING_STATUS = 'pending'
 | 
			
		||||
    ONLINE_STATUS = 'online'
 | 
			
		||||
    CANCELED_STATUS = 'canceled'
 | 
			
		||||
 | 
			
		||||
    VM_STATUS_CHOICES = (
 | 
			
		||||
        (PENDING_STATUS, 'Pending for activation'),
 | 
			
		||||
        (ONLINE_STATUS, 'Online'),
 | 
			
		||||
        (CANCELED_STATUS, 'Canceled')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # DJANGO = 'django'
 | 
			
		||||
    # RAILS = 'rails'
 | 
			
		||||
    # NODEJS = 'nodejs'
 | 
			
		||||
 | 
			
		||||
    # VM_CONFIGURATION = (
 | 
			
		||||
    #     (DJANGO, 'Ubuntu 14.04, Django'),
 | 
			
		||||
    #     (RAILS, 'Ubuntu 14.04, Rails'),
 | 
			
		||||
    #     (NODEJS, 'Debian, NodeJS'),
 | 
			
		||||
    # )
 | 
			
		||||
 | 
			
		||||
    VM_CONFIGURATION = (
 | 
			
		||||
        ('debian', 'Debian 8'),
 | 
			
		||||
        ('ubuntu', 'Ubuntu 16.06'),
 | 
			
		||||
        ('devuan', 'Devuan 1'),
 | 
			
		||||
        ('centos', 'CentOS 7')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    permissions = ('view_virtualmachineplan',
 | 
			
		||||
                   'cancel_virtualmachineplan',
 | 
			
		||||
                   'change_virtualmachineplan')
 | 
			
		||||
 | 
			
		||||
    cores = models.IntegerField()
 | 
			
		||||
    memory = models.IntegerField()
 | 
			
		||||
    disk_size = models.IntegerField()
 | 
			
		||||
    vm_type = models.ForeignKey(VirtualMachineType, null=True)
 | 
			
		||||
    price = models.FloatField()
 | 
			
		||||
    public_key = models.TextField(blank=True)
 | 
			
		||||
    status = models.CharField(max_length=20, choices=VM_STATUS_CHOICES, default=PENDING_STATUS)
 | 
			
		||||
    ip = models.CharField(max_length=50, blank=True)
 | 
			
		||||
    configuration = models.CharField(max_length=20, choices=VM_CONFIGURATION)
 | 
			
		||||
    opennebula_id = models.IntegerField(null=True)
 | 
			
		||||
 | 
			
		||||
    objects = VMPlansManager()
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        permissions = (
 | 
			
		||||
            ('view_virtualmachineplan', 'View Virtual Machine Plan'),
 | 
			
		||||
            ('cancel_virtualmachineplan', 'Cancel Virtual Machine Plan'),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.name
 | 
			
		||||
 | 
			
		||||
    # @cached_property
 | 
			
		||||
    # def hosting_company_name(self):
 | 
			
		||||
    #     return self.vm_type.get_hosting_company_display()
 | 
			
		||||
 | 
			
		||||
    # @cached_property
 | 
			
		||||
    # def location(self):
 | 
			
		||||
    #     return self.vm_type.get_location_display()
 | 
			
		||||
 | 
			
		||||
    @cached_property
 | 
			
		||||
    def name(self):
 | 
			
		||||
        name = 'vm-%s' % self.id
 | 
			
		||||
        return name
 | 
			
		||||
 | 
			
		||||
    @cached_property
 | 
			
		||||
    def notifications(self):
 | 
			
		||||
        stripe_customer = StripeCustomer.objects.get(hostingorder__vm_plan=self)
 | 
			
		||||
        backend = stored_messages_settings.STORAGE_BACKEND()
 | 
			
		||||
        messages = backend.inbox_list(stripe_customer.user)
 | 
			
		||||
        return messages
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def create(cls, data, user):
 | 
			
		||||
        instance = cls.objects.create(**data)
 | 
			
		||||
        instance.assign_permissions(user)
 | 
			
		||||
        return instance
 | 
			
		||||
 | 
			
		||||
    def cancel_plan(self, vm_id):
 | 
			
		||||
        self.status = self.CANCELED_STATUS
 | 
			
		||||
        self.save(update_fields=['status'])
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def terminate_opennebula_vm(self, user, vm_id):
 | 
			
		||||
 | 
			
		||||
        opennebula_client = OpenNebulaManager(
 | 
			
		||||
            user.email,
 | 
			
		||||
            user.password,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return opennebula_client.terminate_vm(vm_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def create_opennebula_vm(self, user, specs):
 | 
			
		||||
        # import pdb
 | 
			
		||||
        # pdb.set_trace()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        # Init opennebula manager using given user
 | 
			
		||||
        opennebula_client = OpenNebulaManager(
 | 
			
		||||
            user.email,
 | 
			
		||||
            user.password,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # 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(
 | 
			
		||||
            email=user.email,
 | 
			
		||||
            password=user.password,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # Get vm given the id
 | 
			
		||||
        vm = opennebula_client.get_vm(
 | 
			
		||||
            user.email,
 | 
			
		||||
            vm_id
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # Parse vm data
 | 
			
		||||
        vm_data = OpenNebulaManager.parse_vm(vm)
 | 
			
		||||
 | 
			
		||||
        return vm_data
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_vms(self, user):
 | 
			
		||||
 | 
			
		||||
        # Get opennebula client
 | 
			
		||||
        opennebula_client = OpenNebulaManager(
 | 
			
		||||
            email=user.email,
 | 
			
		||||
            password=user.password,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # Get vm pool
 | 
			
		||||
        vm_pool = opennebula_client.get_vms(user.email)
 | 
			
		||||
 | 
			
		||||
        # Reset total price
 | 
			
		||||
        self.total_price = 0
 | 
			
		||||
        vms = []
 | 
			
		||||
        # Add vm in vm_pool to context
 | 
			
		||||
        for vm in vm_pool:
 | 
			
		||||
            vm_data = OpenNebulaManager.parse_vm(vm)
 | 
			
		||||
            vms.append(vm_data)
 | 
			
		||||
            # self.total_price += price
 | 
			
		||||
        # self.save()
 | 
			
		||||
        return vms
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HostingOrder(AssignPermissionsMixin, models.Model):
 | 
			
		||||
 | 
			
		||||
    ORDER_APPROVED_STATUS = 'Approved'
 | 
			
		||||
    ORDER_DECLINED_STATUS = 'Declined'
 | 
			
		||||
 | 
			
		||||
    vm_plan = models.ForeignKey(VirtualMachinePlan, related_name='hosting_orders')
 | 
			
		||||
    vm_id = models.IntegerField(default=0)
 | 
			
		||||
    customer = models.ForeignKey(StripeCustomer)
 | 
			
		||||
    billing_address = models.ForeignKey(BillingAddress)
 | 
			
		||||
    created_at = models.DateTimeField(auto_now_add=True)
 | 
			
		||||
| 
						 | 
				
			
			@ -272,6 +37,7 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
 | 
			
		|||
    last4 = models.CharField(max_length=4)
 | 
			
		||||
    cc_brand = models.CharField(max_length=10)
 | 
			
		||||
    stripe_charge_id = models.CharField(max_length=100, null=True)
 | 
			
		||||
    price = models.FloatField()
 | 
			
		||||
 | 
			
		||||
    permissions = ('view_hostingorder',)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -288,9 +54,13 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
 | 
			
		|||
        return self.ORDER_APPROVED_STATUS if self.approved else self.ORDER_DECLINED_STATUS
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def create(cls, vm_plan=None, customer=None, billing_address=None):
 | 
			
		||||
        instance = cls.objects.create(vm_plan=vm_plan, customer=customer,
 | 
			
		||||
                                      billing_address=billing_address)
 | 
			
		||||
    def create(cls, price=None, vm_id=None, customer=None, billing_address=None):
 | 
			
		||||
        instance = cls.objects.create(
 | 
			
		||||
            price=price,
 | 
			
		||||
            vm_id=vm_id,
 | 
			
		||||
            customer=customer,
 | 
			
		||||
            billing_address=billing_address
 | 
			
		||||
        )
 | 
			
		||||
        instance.assign_permissions(customer.user)
 | 
			
		||||
        return instance
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -336,17 +106,6 @@ class UserHostingKey(models.Model):
 | 
			
		|||
        # self.save(update_fields=['public_key'])
 | 
			
		||||
        return private_key, public_key
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ManageVM(models.Model):
 | 
			
		||||
    def has_add_permission(self, request):
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def has_delete_permission(self, request, obj=None):
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        managed = False
 | 
			
		||||
 | 
			
		||||
class HostingBill(AssignPermissionsMixin, models.Model):
 | 
			
		||||
    customer = models.ForeignKey(StripeCustomer)
 | 
			
		||||
    billing_address = models.ForeignKey(BillingAddress)
 | 
			
		||||
| 
						 | 
				
			
			@ -367,32 +126,3 @@ class HostingBill(AssignPermissionsMixin, models.Model):
 | 
			
		|||
        instance = cls.objects.create(customer=customer, billing_address=billing_address)
 | 
			
		||||
        return instance
 | 
			
		||||
 | 
			
		||||
    def get_vms(self):
 | 
			
		||||
        email = self.customer.user.email
 | 
			
		||||
        # Get opennebula client
 | 
			
		||||
        opennebula_client = OpenNebulaManager(create_user=False)
 | 
			
		||||
 | 
			
		||||
        # Get vm pool
 | 
			
		||||
        vm_pool = opennebula_client.get_vms(email)
 | 
			
		||||
 | 
			
		||||
        # Reset total price
 | 
			
		||||
        self.total_price = 0
 | 
			
		||||
        vms = []
 | 
			
		||||
        # Add vm in vm_pool to context
 | 
			
		||||
        for vm in vm_pool:
 | 
			
		||||
            vm_data = OpenNebulaManager.parse_vm(vm)
 | 
			
		||||
            self.total_price += vm_data['price']
 | 
			
		||||
            vms.append(vm_data)
 | 
			
		||||
        self.save()
 | 
			
		||||
        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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,7 +78,7 @@
 | 
			
		|||
            </div>
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-sm-6">
 | 
			
		||||
                    {% trans "CH02 ............" %}
 | 
			
		||||
                    {% trans "CH02 0900 0000 6071 8848 8%}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-sm-6">
 | 
			
		||||
                    {% trans "POFICHBEXXX" %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,15 +12,19 @@
 | 
			
		|||
                    {% csrf_token %}
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        Select VM:
 | 
			
		||||
                        <select name="vm_template">
 | 
			
		||||
                            {% for vm in vm_types %}
 | 
			
		||||
                        <select name="vm_template_id">
 | 
			
		||||
                            {% for template in templates %}
 | 
			
		||||
                               
 | 
			
		||||
                                  <option value="{{vm.id}}">CORE: {{vm.cores}}, RAM: {{vm.memory}}, SSD: {{vm.disk_size}}  </option>
 | 
			
		||||
                                  <option value="{{template.id}}">
 | 
			
		||||
                                                CORE: {{template.cores}},
 | 
			
		||||
                                                RAM: {{template.memory}} GiB, 
 | 
			
		||||
                                                SSD: {{template.disk_size}} GiB
 | 
			
		||||
                                  </option>
 | 
			
		||||
                                
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </select>
 | 
			
		||||
                    </div> 
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
<!--                     <div class="form-group">
 | 
			
		||||
                        Select VM Configuration:
 | 
			
		||||
                        <select name="configuration">
 | 
			
		||||
                            {% for config in configuration_options %}
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +33,7 @@
 | 
			
		|||
                                
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </select>
 | 
			
		||||
                    </div>                          
 | 
			
		||||
                    </div>  -->                         
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <button class="btn btn-success" >{% trans "Start VM"%} </button>                         
 | 
			
		||||
                    </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,17 +49,13 @@
 | 
			
		|||
            <h3><b>{% trans "Order summary"%}</b></h3>
 | 
			
		||||
            <hr>
 | 
			
		||||
            <div class="content">
 | 
			
		||||
                <p><b>{% trans "Type"%}</b> <span class="pull-right">{{order.vm_plan.hosting_company_name}}</span></p>
 | 
			
		||||
                <p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cores}}</span></p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Configuration"%}</b> <span class="pull-right">{{order.vm_plan.get_configuration_display}}</span></p>
 | 
			
		||||
                <p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GiB</span></p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Cores"%}</b> <span class="pull-right">{{order.vm_plan.cores}}</span></p>
 | 
			
		||||
                <p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GiB</span></p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Memory"%}</b> <span class="pull-right">{{order.vm_plan.memory}} GiB</span></p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{order.vm_plan.disk_size}} GiB</span></p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <h4>{% trans "Total"%}<p class="pull-right"><b>{{order.vm_plan.price}} CHF</b></p></h4>
 | 
			
		||||
                <h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4>
 | 
			
		||||
            </div>
 | 
			
		||||
            <br/>
 | 
			
		||||
            {% url 'hosting:payment' as payment_url %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,15 +100,14 @@
 | 
			
		|||
							<div class="content">
 | 
			
		||||
								<!-- <p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.location_code}}</span></p> -->
 | 
			
		||||
								<!-- <hr> -->
 | 
			
		||||
								<p><b>Cores</b> <span class="pull-right">{{request.session.vm_specs.cores}}</span></p>
 | 
			
		||||
								<p><b>Cores</b> <span class="pull-right">{{request.session.template.cores}}</span></p>
 | 
			
		||||
								<hr>
 | 
			
		||||
								<p><b>Configuration</b> <span class="pull-right">{{request.session.vm_specs.configuration_display}}</span></p>
 | 
			
		||||
								<p><b>Memory</b> <span class="pull-right">{{request.session.template.memory}} GiB</span></p>
 | 
			
		||||
								<hr>
 | 
			
		||||
								<p><b>Memory</b> <span class="pull-right">{{request.session.vm_specs.memory}} GiB</span></p>
 | 
			
		||||
								<p><b>Disk space</b> <span class="pull-right">{{request.session.template.disk_size}} GiB</span></p>
 | 
			
		||||
								<hr>
 | 
			
		||||
								<p><b>Disk space</b> <span class="pull-right">{{request.session.vm_specs.disk_size}} GiB</span></p>
 | 
			
		||||
								<hr>
 | 
			
		||||
								<h4>Total<p class="pull-right"><b>{{request.session.vm_specs.final_price}} CHF</b></p></h4>
 | 
			
		||||
								<h4>Total<p
 | 
			
		||||
                                    class="pull-right"><b>{{request.session.template.price }} CHF</b></p></h4>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,12 +25,6 @@
 | 
			
		|||
				            		{% trans "Billing"%}
 | 
			
		||||
				            	</a>
 | 
			
		||||
				            </li>
 | 
			
		||||
				            <li>
 | 
			
		||||
				            	<a href="#orders-v" data-toggle="tab">
 | 
			
		||||
				            		<i class="fa fa-credit-card"></i> 
 | 
			
		||||
				            		{% trans "Orders"%}
 | 
			
		||||
				            	</a>
 | 
			
		||||
				            </li>
 | 
			
		||||
				            <li>
 | 
			
		||||
				            	<a href="#status-v" data-toggle="tab">
 | 
			
		||||
				            		<i class="fa fa-signal" aria-hidden="true"></i> {% trans "Status"%}
 | 
			
		||||
| 
						 | 
				
			
			@ -109,55 +103,21 @@
 | 
			
		|||
									</div>
 | 
			
		||||
				            	</div>
 | 
			
		||||
				            </div>
 | 
			
		||||
				            <div class="tab-pane" id="orders-v">
 | 
			
		||||
								<div class="row">
 | 
			
		||||
								  <div class="col-md-12">
 | 
			
		||||
									<table class="table borderless table-hover"> 
 | 
			
		||||
										<h3>Orders</h3> 
 | 
			
		||||
										<br/>
 | 
			
		||||
										<thead> 
 | 
			
		||||
										<tr> 
 | 
			
		||||
											<th>#</th>
 | 
			
		||||
											<th>{% trans "Date"%}</th>
 | 
			
		||||
											<th>{% trans "Amount"%}</th>
 | 
			
		||||
											<th>{% trans "Status"%}</th>
 | 
			
		||||
											<th></th>
 | 
			
		||||
										</tr> 
 | 
			
		||||
										</thead> 
 | 
			
		||||
										<tbody> 
 | 
			
		||||
											{% for order in virtual_machine.hosting_orders.all %}
 | 
			
		||||
											<tr> 
 | 
			
		||||
												<td scope="row">{{order.id}}</td> 
 | 
			
		||||
												<td>{{order.created_at}}</td> 
 | 
			
		||||
												<td>{{order.vm_plan.price}} CHF</td> 
 | 
			
		||||
												<td>{% if order.approved %}
 | 
			
		||||
														<span class="text-success strong">{% trans "Approved"%}</span>
 | 
			
		||||
													{% else%} 
 | 
			
		||||
														<span class="text-danger strong">{% trans "Declined"%}</span>
 | 
			
		||||
													{% endif%}
 | 
			
		||||
												</td> 
 | 
			
		||||
												<td>
 | 
			
		||||
													<button type="button" class="btn btn-default"><a href="{% url 'hosting:orders' order.id %}">{% trans "View Detail"%}</a></button>
 | 
			
		||||
												</td>
 | 
			
		||||
											</tr>
 | 
			
		||||
											{% endfor %}
 | 
			
		||||
										</tbody> 
 | 
			
		||||
									</table>
 | 
			
		||||
								  </div><!--/col-12-->
 | 
			
		||||
								</div><!--/row-->
 | 
			
		||||
				            </div>
 | 
			
		||||
				            <div class="tab-pane" id="status-v">
 | 
			
		||||
				            	<div class="row ">
 | 
			
		||||
									<div class="col-md-12 inline-headers">
 | 
			
		||||
										<h3>{% trans "Current status"%}</h3>
 | 
			
		||||
 | 
			
		||||
										<div  class="pull-right space-above">
 | 
			
		||||
                                            {% if virtual_machine.state == 'ACTIVE' %}
 | 
			
		||||
                                                <span class="h3 label label-success"><strong> {{virtual_machine.state}}</strong></span>
 | 
			
		||||
                                            {% elif  virtual_machine.state == 'POWEROFF' %}
 | 
			
		||||
                                                <span class="h3 label label-danger"><strong>{{virtual_machine.state}}</strong></span>
 | 
			
		||||
                                            {% else %}
 | 
			
		||||
                                                <span class="h3 label label-warning"><strong>{{virtual_machine.state}}</strong></span>
 | 
			
		||||
											{% if virtual_machine.state == 'PENDING' %}
 | 
			
		||||
												<span class="label
 | 
			
		||||
                                                    label-warning"><strong>Pending</strong></span>
 | 
			
		||||
											{% elif  virtual_machine.state == 'ACTIVE' %}
 | 
			
		||||
												<span class="label
 | 
			
		||||
                                                    label-success"><strong>Online</strong></span>
 | 
			
		||||
											{% elif  virtual_machine.state == 'FAILED'%}
 | 
			
		||||
												<span class="label
 | 
			
		||||
                                                    label-danger"><strong>Failed</strong></span>
 | 
			
		||||
											{% endif %}
 | 
			
		||||
										</div>
 | 
			
		||||
									</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -166,11 +126,12 @@
 | 
			
		|||
				            	<div class="row">
 | 
			
		||||
									<div class="col-md-12 space-above-big">
 | 
			
		||||
										<div class="pull-right">
 | 
			
		||||
											<form method="POST" id="virtual_machine_cancel_form" class="cancel-form" action="{% url 'hosting:virtual_machines' virtual_machine.id %}">
 | 
			
		||||
											<form method="POST"
 | 
			
		||||
                 id="virtual_machine_cancel_form" class="cancel-form" action="{% url 'hosting:virtual_machines' virtual_machine.vm_id %}">
 | 
			
		||||
											{% csrf_token %} 
 | 
			
		||||
											</form>	
 | 
			
		||||
												
 | 
			
		||||
												<button type="text" data-href="{% url 'hosting:virtual_machines' virtual_machine.id %}" data-toggle="modal" data-target="#confirm-cancel" class="btn btn-danger">{% trans "Terminate Virtual Machine"%}</button>
 | 
			
		||||
												<button type="text" data-href="{% url 'hosting:virtual_machines' virtual_machine.vm_id %}" data-toggle="modal" data-target="#confirm-cancel" class="btn btn-danger">{% trans "Terminate Virtual Machine"%}</button>
 | 
			
		||||
																						
 | 
			
		||||
										</div>
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +155,7 @@
 | 
			
		|||
									                {% trans "Terminate your Virtual Machine"%}
 | 
			
		||||
									            </div>
 | 
			
		||||
									            <div class="modal-body">
 | 
			
		||||
									                {% trans "Are you sure do you want to cancel your Virtual Machine "%} {{vm.virtual_machine}}  {% trans "plan?"%}
 | 
			
		||||
									                {% trans "Are you sure do you want to cancel your Virtual Machine "%} {{virtual_machine.name}}  {% trans "plan?"%}
 | 
			
		||||
									            </div>
 | 
			
		||||
									            <div class="modal-footer">
 | 
			
		||||
									                <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Cancel"%}</button>
 | 
			
		||||
| 
						 | 
				
			
			@ -220,12 +181,3 @@
 | 
			
		|||
</div>
 | 
			
		||||
 | 
			
		||||
{%endblock%}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,15 +30,15 @@
 | 
			
		|||
				</tr>
 | 
			
		||||
				</thead>
 | 
			
		||||
				<tbody> 
 | 
			
		||||
					{% for vm in vms_opennebula %}
 | 
			
		||||
					{% for vm in vms %}
 | 
			
		||||
					<tr>
 | 
			
		||||
						<td scope="row">{{vm.name}}</td> 
 | 
			
		||||
						<td>{{vm.price|floatformat:2}} CHF</td> 
 | 
			
		||||
						<td scope="row">{{vm.vm_id}}</td> 
 | 
			
		||||
						<td>{{vm.price}} CHF</td> 
 | 
			
		||||
						<td>
 | 
			
		||||
                           
 | 
			
		||||
							{% if vm.state == 'ACTIVE' %}
 | 
			
		||||
								<span class="h3 label label-success"><strong> {{vm.state}}</strong></span>
 | 
			
		||||
							{% elif  vm.state == 'POWEROFF' %}
 | 
			
		||||
							{% elif  vm.state == 'FAILED' %}
 | 
			
		||||
								<span class="h3 label label-danger"><strong>{{vm.state}}</strong></span>
 | 
			
		||||
							{% else %}
 | 
			
		||||
								<span class="h3 label label-warning"><strong>{{vm.state}}</strong></span>
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +46,8 @@
 | 
			
		|||
 | 
			
		||||
						</td> 
 | 
			
		||||
						<td>
 | 
			
		||||
                            <button type="button" class="btn btn-default"><a href="{% url 'hosting:virtual_machines' vm.id %}">{% trans "View Detail"%}</a></button>
 | 
			
		||||
                            <button type="button" class="btn btn-default"><a
 | 
			
		||||
                                    href="{% url 'hosting:virtual_machines' vm.vm_id %}">{% trans "View Detail"%}</a></button>
 | 
			
		||||
                        </td>
 | 
			
		||||
					</tr>
 | 
			
		||||
					{% endfor %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										251
									
								
								hosting/views.py
									
										
									
									
									
								
							
							
						
						
									
										251
									
								
								hosting/views.py
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -20,16 +20,18 @@ from stored_messages.models import Message
 | 
			
		|||
from stored_messages.api import mark_read
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from membership.models import CustomUser, StripeCustomer
 | 
			
		||||
from utils.stripe_utils import StripeUtils
 | 
			
		||||
from utils.forms import BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm
 | 
			
		||||
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
 | 
			
		||||
from utils.mailer import BaseEmail
 | 
			
		||||
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, HostingBill, UserHostingKey
 | 
			
		||||
from .models import HostingOrder, HostingBill, UserHostingKey
 | 
			
		||||
from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyForm
 | 
			
		||||
from .mixins import ProcessVMSelectionMixin
 | 
			
		||||
from .opennebula_functions import HostingManageVMAdmin, OpenNebulaManager
 | 
			
		||||
 | 
			
		||||
from opennebula_api.models import OpenNebulaManager
 | 
			
		||||
from opennebula_api.serializers import VirtualMachineSerializer,\
 | 
			
		||||
                                       VirtualMachineTemplateSerializer
 | 
			
		||||
 | 
			
		||||
from oca.exceptions import OpenNebulaException
 | 
			
		||||
from oca.pool import WrongNameError
 | 
			
		||||
| 
						 | 
				
			
			@ -387,57 +389,26 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
			
		|||
 | 
			
		||||
            context = self.get_context_data()
 | 
			
		||||
 | 
			
		||||
            specifications = request.session.get('vm_specs')
 | 
			
		||||
            specifications = request.session.get('template')
 | 
			
		||||
 | 
			
		||||
            vm_template = specifications.get('vm_template', 1)
 | 
			
		||||
            vm_template_id = specifications.get('id', 1)
 | 
			
		||||
 | 
			
		||||
            vm_type = VirtualMachineType.objects.get(id=vm_template)
 | 
			
		||||
 | 
			
		||||
            specs = vm_type.get_specs()
 | 
			
		||||
 | 
			
		||||
            final_price = vm_type.calculate_price()
 | 
			
		||||
 | 
			
		||||
            plan_data = {
 | 
			
		||||
                'vm_type': vm_type,
 | 
			
		||||
                'configuration': specifications.get(
 | 
			
		||||
                    'configuration',
 | 
			
		||||
                    'django'
 | 
			
		||||
                ),
 | 
			
		||||
                'price': final_price
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            plan_data.update(specs)
 | 
			
		||||
            final_price = specifications.get('price', 1)
 | 
			
		||||
 | 
			
		||||
            token = form.cleaned_data.get('token')
 | 
			
		||||
 | 
			
		||||
            owner = self.request.user
 | 
			
		||||
 | 
			
		||||
            # Get or create stripe customer
 | 
			
		||||
            customer = StripeCustomer.get_or_create(email=self.request.user.email,
 | 
			
		||||
            customer = StripeCustomer.get_or_create(email=owner.email,
 | 
			
		||||
                                                    token=token)
 | 
			
		||||
            if not customer:
 | 
			
		||||
                form.add_error("__all__", "Invalid credit card")
 | 
			
		||||
                return self.render_to_response(self.get_context_data(form=form))
 | 
			
		||||
 | 
			
		||||
            # Create Virtual Machine Plan
 | 
			
		||||
            plan = VirtualMachinePlan.create(plan_data, request.user)
 | 
			
		||||
 | 
			
		||||
            # Create Billing Address
 | 
			
		||||
            billing_address = form.save()
 | 
			
		||||
 | 
			
		||||
            # Create Billing Address for User if he does not have one
 | 
			
		||||
            if not customer.user.billing_addresses.count():
 | 
			
		||||
                billing_address_data.update({
 | 
			
		||||
                    'user': customer.user.id
 | 
			
		||||
                })
 | 
			
		||||
                billing_address_user_form = UserBillingAddressForm(billing_address_data)
 | 
			
		||||
                billing_address_user_form.is_valid()
 | 
			
		||||
                billing_address_user_form.save()
 | 
			
		||||
 | 
			
		||||
            # Create a Hosting Order
 | 
			
		||||
            order = HostingOrder.create(vm_plan=plan, customer=customer,
 | 
			
		||||
                                        billing_address=billing_address)
 | 
			
		||||
            # Create a Hosting Bill
 | 
			
		||||
            bill = HostingBill.create(customer=customer, billing_address=billing_address)
 | 
			
		||||
 | 
			
		||||
            # Make stripe charge to a customer
 | 
			
		||||
            stripe_utils = StripeUtils()
 | 
			
		||||
            charge_response = stripe_utils.make_charge(amount=final_price,
 | 
			
		||||
| 
						 | 
				
			
			@ -454,11 +425,11 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
			
		|||
 | 
			
		||||
            charge = charge_response.get('response_object')
 | 
			
		||||
 | 
			
		||||
            # Associate an order with a stripe payment
 | 
			
		||||
            order.set_stripe_charge(charge)
 | 
			
		||||
 | 
			
		||||
            # If the Stripe payment was successed, set order status approved
 | 
			
		||||
            order.set_approved()
 | 
			
		||||
            # Create OpenNebulaManager
 | 
			
		||||
            manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                        password=owner.password,
 | 
			
		||||
                                        create_user=True)
 | 
			
		||||
            template = manager.get_template(vm_template_id)
 | 
			
		||||
 | 
			
		||||
            # Get user ssh key
 | 
			
		||||
            try:
 | 
			
		||||
| 
						 | 
				
			
			@ -466,26 +437,46 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
			
		|||
                    user=self.request.user
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                # Add ssh_key to specs
 | 
			
		||||
                specs.update({
 | 
			
		||||
                    'ssh_key': user_key.public_key
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
            except UserHostingKey.DoesNotExist:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
            # Create a vm using logged user
 | 
			
		||||
            opennebula_vm_id = VirtualMachinePlan.create_opennebula_vm(
 | 
			
		||||
                self.request.user,
 | 
			
		||||
                specs
 | 
			
		||||
            vm_id = manager.create_vm(
 | 
			
		||||
                vm_template_id,
 | 
			
		||||
                ssh_key=user_key.public_key
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            plan.opennebula_id = opennebula_vm_id
 | 
			
		||||
            plan.save()
 | 
			
		||||
            # Create a Hosting Order
 | 
			
		||||
            order = HostingOrder.create(
 | 
			
		||||
                price=final_price,
 | 
			
		||||
                vm_id=vm_id,
 | 
			
		||||
                customer=customer,
 | 
			
		||||
                billing_address=billing_address
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            # Create a Hosting Bill
 | 
			
		||||
            bill = HostingBill.create(customer=customer, billing_address=billing_address)
 | 
			
		||||
 | 
			
		||||
            # Create Billing Address for User if he does not have one
 | 
			
		||||
            if not customer.user.billing_addresses.count():
 | 
			
		||||
                billing_address_data.update({
 | 
			
		||||
                    'user': customer.user.id
 | 
			
		||||
                })
 | 
			
		||||
                billing_address_user_form = UserBillingAddressForm(billing_address_data)
 | 
			
		||||
                billing_address_user_form.is_valid()
 | 
			
		||||
                billing_address_user_form.save()
 | 
			
		||||
 | 
			
		||||
            # Associate an order with a stripe payment
 | 
			
		||||
            order.set_stripe_charge(charge)
 | 
			
		||||
 | 
			
		||||
            # If the Stripe payment was successed, set order status approved
 | 
			
		||||
            order.set_approved()
 | 
			
		||||
 | 
			
		||||
            vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data
 | 
			
		||||
 | 
			
		||||
            # Send notification to ungleich as soon as VM has been booked
 | 
			
		||||
            context = {
 | 
			
		||||
                'vm': plan,
 | 
			
		||||
                'vm': vm,
 | 
			
		||||
                'order': order,
 | 
			
		||||
                'base_url': "{0}://{1}".format(request.scheme, request.get_host())
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -512,6 +503,18 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai
 | 
			
		|||
    permission_required = ['view_hostingorder']
 | 
			
		||||
    model = HostingOrder
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        # Get context
 | 
			
		||||
        context = super(DetailView, self).get_context_data(**kwargs)
 | 
			
		||||
        obj = self.get_object()
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                    password=owner.password,
 | 
			
		||||
                                    create_user=True)
 | 
			
		||||
        vm = manager.get_vm(obj.vm_id)
 | 
			
		||||
        context['vm'] = VirtualMachineSerializer(vm).data
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OrdersHostingListView(LoginRequiredMixin, ListView):
 | 
			
		||||
    template_name = "hosting/orders.html"
 | 
			
		||||
| 
						 | 
				
			
			@ -537,24 +540,17 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView):
 | 
			
		|||
    template_name = "hosting/virtual_machines.html"
 | 
			
		||||
    login_url = reverse_lazy('hosting:login')
 | 
			
		||||
    context_object_name = "vms"
 | 
			
		||||
    model = VirtualMachinePlan
 | 
			
		||||
    paginate_by = 10
 | 
			
		||||
    ordering = '-id'
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super(VirtualMachinesPlanListView, self).get_context_data(**kwargs)
 | 
			
		||||
        context.update({
 | 
			
		||||
            '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.))
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        self.queryset = VirtualMachinePlan.objects.active(user)
 | 
			
		||||
        return super(VirtualMachinesPlanListView, self).get_queryset()
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                    password=owner.password,
 | 
			
		||||
                                    create_user=True)
 | 
			
		||||
        queryset = manager.get_vms()
 | 
			
		||||
        serializer = VirtualMachineSerializer(queryset, many=True)
 | 
			
		||||
        return serializer.data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CreateVirtualMachinesView(LoginRequiredMixin, View):
 | 
			
		||||
| 
						 | 
				
			
			@ -574,107 +570,70 @@ 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
 | 
			
		||||
 | 
			
		||||
        context = {
 | 
			
		||||
            'vm_types': VirtualMachineType.get_serialized_vm_types(),
 | 
			
		||||
            'configuration_options': VirtualMachinePlan.VM_CONFIGURATION
 | 
			
		||||
            'templates': data,
 | 
			
		||||
        }
 | 
			
		||||
        # context = {}
 | 
			
		||||
        return render(request, self.template_name, context)
 | 
			
		||||
 | 
			
		||||
    def post(self, request):
 | 
			
		||||
        configuration = request.POST.get('configuration')
 | 
			
		||||
        configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
 | 
			
		||||
        vm_template = request.POST.get('vm_template')
 | 
			
		||||
        vm_type = VirtualMachineType.objects.get(id=vm_template)
 | 
			
		||||
        vm_specs = vm_type.get_specs()
 | 
			
		||||
        vm_specs.update({
 | 
			
		||||
            'configuration_display': configuration_display,
 | 
			
		||||
            'configuration': configuration,
 | 
			
		||||
            'final_price': vm_type.final_price,
 | 
			
		||||
            'vm_template': vm_template
 | 
			
		||||
        })
 | 
			
		||||
        request.session['vm_specs'] = vm_specs
 | 
			
		||||
        template_id = int(request.POST.get('vm_template_id'))
 | 
			
		||||
        template = OpenNebulaManager().get_template(template_id)
 | 
			
		||||
        data = VirtualMachineTemplateSerializer(template).data
 | 
			
		||||
        request.session['template'] = data
 | 
			
		||||
        return redirect(reverse('hosting:payment'))
 | 
			
		||||
 | 
			
		||||
    # def get_queryset(self):
 | 
			
		||||
    #     # hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin)
 | 
			
		||||
    #     # print(hosting_admin.show_vms(self.request))
 | 
			
		||||
    #     user = self.request.user
 | 
			
		||||
    #     self.queryset = VirtualMachinePlan.objects.active(user)
 | 
			
		||||
    #     return super(VirtualMachinesPlanListView, self).get_queryset()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
 | 
			
		||||
class VirtualMachineView(LoginRequiredMixin, View):
 | 
			
		||||
    template_name = "hosting/virtual_machine_detail.html"
 | 
			
		||||
    login_url = reverse_lazy('hosting:login')
 | 
			
		||||
    # model = VirtualMachinePlan
 | 
			
		||||
    # context_object_name = "virtual_machine"
 | 
			
		||||
    permission_required = []
 | 
			
		||||
    # fields = '__all__'
 | 
			
		||||
 | 
			
		||||
    # def get_context_data(self, **kwargs):
 | 
			
		||||
    #     vm_plan = get_object()
 | 
			
		||||
    #     context = super(VirtualMachineView, self).get_context_data(**kwargs)
 | 
			
		||||
    #     context.update({
 | 
			
		||||
    #         'opennebula_vm': VirtualMachinePlan.get_vm(
 | 
			
		||||
    #             self.request.user.email,
 | 
			
		||||
    #             opennebula_id
 | 
			
		||||
    #         )
 | 
			
		||||
    #     })
 | 
			
		||||
    #     return context
 | 
			
		||||
 | 
			
		||||
    # def get_object(self, queryset=None):
 | 
			
		||||
    #     # if queryset is None:
 | 
			
		||||
    #     #     queryset = self.get_queryset()
 | 
			
		||||
    #     # Next, try looking up by primary key.
 | 
			
		||||
    #     vm_id = self.kwargs.get(self.pk_url_kwarg)
 | 
			
		||||
    #     try:
 | 
			
		||||
    #         return VirtualMachinePlan.get_vm(
 | 
			
		||||
    #             self.request.user.email,
 | 
			
		||||
    #             vm_id
 | 
			
		||||
    #         )
 | 
			
		||||
    #     except Exception as error:
 | 
			
		||||
    #         raise Http404()
 | 
			
		||||
 | 
			
		||||
    def get_object(self):
 | 
			
		||||
        opennebula_vm_id = self.kwargs.get('pk')
 | 
			
		||||
        opennebula_vm = None
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        vm = None
 | 
			
		||||
        manager = OpenNebulaManager(
 | 
			
		||||
            email=owner.email,
 | 
			
		||||
            password=owner.password,
 | 
			
		||||
            create_user=True
 | 
			
		||||
        )
 | 
			
		||||
        vm_id = self.kwargs.get('pk')
 | 
			
		||||
        try:
 | 
			
		||||
            opennebula_vm = VirtualMachinePlan.objects.get(opennebula_id=opennebula_vm_id)
 | 
			
		||||
            vm = manager.get_vm(vm_id)
 | 
			
		||||
        except Exception as error:
 | 
			
		||||
            print(error)
 | 
			
		||||
            raise Http404()
 | 
			
		||||
        return opennebula_vm
 | 
			
		||||
        return vm
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        final_url = reverse('hosting:virtual_machines')
 | 
			
		||||
        return final_url
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        opennebula_vm_id = self.kwargs.get('pk')
 | 
			
		||||
        try:
 | 
			
		||||
            opennebula_vm = VirtualMachinePlan.get_vm(
 | 
			
		||||
                self.request.user,
 | 
			
		||||
                opennebula_vm_id
 | 
			
		||||
            )
 | 
			
		||||
        except Exception as error:
 | 
			
		||||
            print(error)
 | 
			
		||||
            raise Http404()
 | 
			
		||||
 | 
			
		||||
        vm = self.get_object()
 | 
			
		||||
        serializer = VirtualMachineSerializer(vm)
 | 
			
		||||
        context = {
 | 
			
		||||
            'virtual_machine': opennebula_vm,
 | 
			
		||||
            'virtual_machine': serializer.data,
 | 
			
		||||
        }
 | 
			
		||||
        # context = {}
 | 
			
		||||
        return render(request, self.template_name, context)
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        vm = self.get_object()
 | 
			
		||||
 | 
			
		||||
        opennebula_vm_id = self.kwargs.get('pk')
 | 
			
		||||
 | 
			
		||||
        terminated = VirtualMachinePlan.terminate_opennebula_vm(
 | 
			
		||||
            self.request.user,
 | 
			
		||||
            opennebula_vm_id
 | 
			
		||||
        manager = OpenNebulaManager(
 | 
			
		||||
            email=owner.email,
 | 
			
		||||
            password=owner.password,
 | 
			
		||||
            create_user=True
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        terminated = manager.delete_vm(
 | 
			
		||||
            vm.id
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if not terminated:
 | 
			
		||||
| 
						 | 
				
			
			@ -684,8 +643,6 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
 | 
			
		|||
            )
 | 
			
		||||
            return HttpResponseRedirect(self.get_success_url())
 | 
			
		||||
 | 
			
		||||
        #vm.cancel_plan()
 | 
			
		||||
 | 
			
		||||
        context = {
 | 
			
		||||
            'vm': vm,
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
 | 
			
		||||
| 
						 | 
				
			
			@ -735,10 +692,14 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV
 | 
			
		|||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        # Get context
 | 
			
		||||
        context = super(DetailView, self).get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                    password=owner.password,
 | 
			
		||||
                                    create_user=True)
 | 
			
		||||
        # Get vms
 | 
			
		||||
        try:
 | 
			
		||||
            context['vms'] = self.get_object().get_vms()
 | 
			
		||||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
        queryset = manager.get_vms()
 | 
			
		||||
        vms = VirtualMachineSerializer(queryset, many=True).data
 | 
			
		||||
        context['vms'] = vms
 | 
			
		||||
 | 
			
		||||
        return context
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,40 +0,0 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.9.4 on 2017-05-09 14:36
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    initial = True
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='VirtualMachine',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
			
		||||
                ('opennebula_id', models.IntegerField()),
 | 
			
		||||
            ],
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='VirtualMachineTemplate',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
			
		||||
                ('opennebula_id', models.IntegerField()),
 | 
			
		||||
                ('base_price', models.FloatField()),
 | 
			
		||||
                ('memory_price', models.FloatField()),
 | 
			
		||||
                ('core_price', models.FloatField()),
 | 
			
		||||
                ('disk_size_price', models.FloatField()),
 | 
			
		||||
            ],
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='virtualmachine',
 | 
			
		||||
            name='template',
 | 
			
		||||
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='opennebula_api.VirtualMachineTemplate'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,110 +1,14 @@
 | 
			
		|||
import oca
 | 
			
		||||
import socket
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.utils.functional import cached_property
 | 
			
		||||
 | 
			
		||||
from oca.pool import WrongNameError
 | 
			
		||||
 | 
			
		||||
class VirtualMachineTemplate(models.Model):
 | 
			
		||||
    """This class represents an opennebula template."""
 | 
			
		||||
    opennebula_id = models.IntegerField()
 | 
			
		||||
    base_price = models.FloatField()
 | 
			
		||||
    memory_price = models.FloatField()
 | 
			
		||||
    core_price = models.FloatField()
 | 
			
		||||
    disk_size_price = models.FloatField()
 | 
			
		||||
 | 
			
		||||
    def calculate_price(self):
 | 
			
		||||
        template = OpenNebulaManager()._get_template(self.opennebula_id).template
 | 
			
		||||
 | 
			
		||||
        price = int(template.vcpu) * self.core_price
 | 
			
		||||
        price += int(template.memory) / 1024 * self.memory_price
 | 
			
		||||
        try:
 | 
			
		||||
            price += int(template.disk.size) / 1024 * self.disk_size_price
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            for disk in template.disks:
 | 
			
		||||
                price += int(disk.size) / 1024 * self.disk_size_price
 | 
			
		||||
        return price
 | 
			
		||||
 | 
			
		||||
    def get_name(self):
 | 
			
		||||
 | 
			
		||||
        template = OpenNebulaManager()._get_template(template_id=self.opennebula_id)
 | 
			
		||||
        return template.name
 | 
			
		||||
 | 
			
		||||
    def get_cores(self):
 | 
			
		||||
 | 
			
		||||
        template = OpenNebulaManager()._get_template(template_id=self.opennebula_id).template
 | 
			
		||||
        return int(template.vcpu)
 | 
			
		||||
    
 | 
			
		||||
    def get_disk_size(self):
 | 
			
		||||
 | 
			
		||||
        template = OpenNebulaManager()._get_template(template_id=self.opennebula_id).template
 | 
			
		||||
        disk_size = 0
 | 
			
		||||
        for disk in template.disks:
 | 
			
		||||
            disk_size += int(disk.size)
 | 
			
		||||
        return disk_size / 1024
 | 
			
		||||
 | 
			
		||||
    def get_memory(self):
 | 
			
		||||
 | 
			
		||||
        template = OpenNebulaManager()._get_template(template_id=self.opennebula_id).template
 | 
			
		||||
        return int(template.memory) / 1024
 | 
			
		||||
 | 
			
		||||
class VirtualMachine(models.Model):
 | 
			
		||||
    """This class represents an opennebula virtual machine."""
 | 
			
		||||
    opennebula_id = models.IntegerField()
 | 
			
		||||
    vm_template = models.ForeignKey(VirtualMachineTemplate)
 | 
			
		||||
 | 
			
		||||
    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 get_name(self):
 | 
			
		||||
            
 | 
			
		||||
        vm = OpenNebulaManager()._get_vm(vm_id=self.opennebula_id)
 | 
			
		||||
        return vm.name
 | 
			
		||||
 | 
			
		||||
    def get_cores(self):
 | 
			
		||||
 | 
			
		||||
        return self.vm_template.get_cores()
 | 
			
		||||
    
 | 
			
		||||
    def get_disk_size(self):
 | 
			
		||||
        
 | 
			
		||||
        return self.vm_template.get_disk_size()
 | 
			
		||||
 | 
			
		||||
    def get_memory(self):
 | 
			
		||||
 | 
			
		||||
        return self.vm_template.get_memory()
 | 
			
		||||
 | 
			
		||||
    def get_id(self):
 | 
			
		||||
 | 
			
		||||
        vm = OpenNebulaManager()._get_vm(vm_id=self.opennebula_id)
 | 
			
		||||
        return vm.id
 | 
			
		||||
 | 
			
		||||
    def get_ip(self):
 | 
			
		||||
 | 
			
		||||
        vm = OpenNebulaManager()._get_vm(vm_id=self.opennebula_id)
 | 
			
		||||
        try:
 | 
			
		||||
            return vm.user_template.ungleich_public_ip
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            return '-'
 | 
			
		||||
 | 
			
		||||
    def get_state(self):
 | 
			
		||||
 | 
			
		||||
        vm = OpenNebulaManager()._get_vm(vm_id=self.opennebula_id)
 | 
			
		||||
        return self.VM_STATE.get(str(vm.state))
 | 
			
		||||
 | 
			
		||||
    def get_price(self):
 | 
			
		||||
        return self.vm_template.calculate_price()
 | 
			
		||||
from oca.exceptions import OpenNebulaException
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
class OpenNebulaManager():
 | 
			
		||||
    """This class represents an opennebula manager."""
 | 
			
		||||
| 
						 | 
				
			
			@ -175,8 +79,13 @@ class OpenNebulaManager():
 | 
			
		|||
 | 
			
		||||
    def _get_vm_pool(self):
 | 
			
		||||
        try:
 | 
			
		||||
           vm_pool = oca.VirtualMachinePool(self.oneadmin_client)
 | 
			
		||||
            vm_pool = oca.VirtualMachinePool(self.client)
 | 
			
		||||
            vm_pool.info()
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            print('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(
 | 
			
		||||
| 
						 | 
				
			
			@ -186,19 +95,25 @@ class OpenNebulaManager():
 | 
			
		|||
            raise ConnectionRefusedError
 | 
			
		||||
        return vm_pool
 | 
			
		||||
 | 
			
		||||
    def get_vms(self):
 | 
			
		||||
        return self._get_vm_pool()
 | 
			
		||||
   
 | 
			
		||||
    def _get_vm(self, vm_id):
 | 
			
		||||
    def get_vm(self, vm_id):
 | 
			
		||||
        vm_pool = self._get_vm_pool()
 | 
			
		||||
        # Get virtual machines from all users 
 | 
			
		||||
        vm_pool.info(filter=-2)
 | 
			
		||||
        return vm_pool.get_by_id(vm_id)
 | 
			
		||||
        return vm_pool.get_by_id(int(vm_id))
 | 
			
		||||
 | 
			
		||||
    def create_vm(self, template_id):
 | 
			
		||||
        template_pool = self._get_template_pool()
 | 
			
		||||
 | 
			
		||||
        template = template_pool.get_by_id(template_id)
 | 
			
		||||
 | 
			
		||||
        vm_id = template.instantiate()
 | 
			
		||||
    #TODO: get app with id 
 | 
			
		||||
    def create_vm(self, template_id, app_id=None, ssh_key=None):
 | 
			
		||||
        extra_template = "<CONTEXT><SSH_PUBLIC_KEY>{ssh_key}</SSH_PUBLIC_KEY></CONTEXT>".format(
 | 
			
		||||
            ssh_key=ssh_key
 | 
			
		||||
        )
 | 
			
		||||
        vm_id = self.oneadmin_client.call(
 | 
			
		||||
            oca.VmTemplate.METHODS['instantiate'],
 | 
			
		||||
            template_id,
 | 
			
		||||
            '',
 | 
			
		||||
            False,
 | 
			
		||||
            extra_template
 | 
			
		||||
        )
 | 
			
		||||
        try:
 | 
			
		||||
            self.oneadmin_client.call(
 | 
			
		||||
                oca.VirtualMachine.METHODS['chown'],
 | 
			
		||||
| 
						 | 
				
			
			@ -207,12 +122,33 @@ class OpenNebulaManager():
 | 
			
		|||
                self.opennebula_user.group_ids[0]
 | 
			
		||||
            )
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            pass
 | 
			
		||||
            print('Could not change owner, opennebula_user is not set.')
 | 
			
		||||
        return vm_id
 | 
			
		||||
 | 
			
		||||
    def delete_vm(self, vm_id):
 | 
			
		||||
        vm = self._get_vm(vm_id)
 | 
			
		||||
        vm.delete()
 | 
			
		||||
        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.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
 | 
			
		||||
 | 
			
		||||
    def _get_template_pool(self):
 | 
			
		||||
        try:
 | 
			
		||||
| 
						 | 
				
			
			@ -227,19 +163,31 @@ class OpenNebulaManager():
 | 
			
		|||
            raise ConnectionRefusedError
 | 
			
		||||
        return template_pool
 | 
			
		||||
 | 
			
		||||
    def _get_template(self, template_id):
 | 
			
		||||
    def get_templates(self):
 | 
			
		||||
        public_templates = [
 | 
			
		||||
                template 
 | 
			
		||||
                for template in self._get_template_pool()
 | 
			
		||||
                if 'public-' in template.name 
 | 
			
		||||
                ]
 | 
			
		||||
        return public_templates 
 | 
			
		||||
    def get_template(self, template_id):
 | 
			
		||||
        template_pool = self._get_template_pool()
 | 
			
		||||
        return template_pool.get_by_id(template_id)
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    def create_template(self, name, cores, memory, disk_size):
 | 
			
		||||
    def create_template(self, name, cores, memory, disk_size, core_price, memory_price,
 | 
			
		||||
                        disk_size_price, ssh='' ):
 | 
			
		||||
        """Create and add a new template to opennebula.
 | 
			
		||||
        :param name:      A string representation describing the template.
 | 
			
		||||
                          Used as label in view.
 | 
			
		||||
        :param cores:     Amount of virtual cpu cores for the VM.
 | 
			
		||||
        :param memory:    Amount of RAM for the VM (MB)
 | 
			
		||||
        :param disk_size: Amount of disk space for VM (MB)
 | 
			
		||||
        :param memory:  Amount of RAM for the VM (GB)
 | 
			
		||||
        :param disk_size:    Amount of disk space for VM (GB)
 | 
			
		||||
        :param core_price:     Price of virtual cpu for the VM per core.
 | 
			
		||||
        :param memory_price:  Price of RAM for the VM per GB
 | 
			
		||||
        :param disk_size_price:    Price of disk space for VM per GB
 | 
			
		||||
        :param ssh: User public ssh key
 | 
			
		||||
        """
 | 
			
		||||
        template_string_formatter = """<TEMPLATE>
 | 
			
		||||
                                        <NAME>{name}</NAME>
 | 
			
		||||
| 
						 | 
				
			
			@ -251,6 +199,10 @@ class OpenNebulaManager():
 | 
			
		|||
                                         <SIZE>{size}</SIZE>
 | 
			
		||||
                                         <DEV_PREFIX>vd</DEV_PREFIX>
 | 
			
		||||
                                        </DISK>
 | 
			
		||||
                                        <CPU_COST>{cpu_cost}</CPU_COST>
 | 
			
		||||
                                        <MEMORY_COST>{memory_cost}</MEMORY_COST>
 | 
			
		||||
                                        <DISK_COST>{disk_cost}</DISK_COST>
 | 
			
		||||
                                        <SSH_PUBLIC_KEY>{ssh}</SSH_PUBLIC_KEY>
 | 
			
		||||
                                       </TEMPLATE>
 | 
			
		||||
                                       """
 | 
			
		||||
        template_id = oca.VmTemplate.allocate(
 | 
			
		||||
| 
						 | 
				
			
			@ -260,7 +212,12 @@ class OpenNebulaManager():
 | 
			
		|||
                vcpu=cores,
 | 
			
		||||
                cpu=0.1*cores,
 | 
			
		||||
                size=1024 * disk_size,
 | 
			
		||||
                memory=1024 * memory
 | 
			
		||||
                memory=1024 * memory,
 | 
			
		||||
                # * 10 because we set cpu to *0.1
 | 
			
		||||
                cpu_cost=10*core_price,
 | 
			
		||||
                memory_cost=memory_price,
 | 
			
		||||
                disk_cost=disk_size_price,
 | 
			
		||||
                ssh=ssh
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -269,5 +226,3 @@ class OpenNebulaManager():
 | 
			
		|||
    def delete_template(self, template_id):
 | 
			
		||||
        self.oneadmin_client.call(oca.VmTemplate.METHODS['delete'], template_id, False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,91 +3,117 @@ import oca
 | 
			
		|||
from rest_framework import serializers
 | 
			
		||||
 | 
			
		||||
from oca import OpenNebulaException
 | 
			
		||||
from oca.template import VmTemplate
 | 
			
		||||
 | 
			
		||||
from .models import VirtualMachine, VirtualMachineTemplate, OpenNebulaManager
 | 
			
		||||
from .models import OpenNebulaManager
 | 
			
		||||
 | 
			
		||||
class VirtualMachineTemplateSerializer(serializers.ModelSerializer):
 | 
			
		||||
class VirtualMachineTemplateSerializer(serializers.Serializer):
 | 
			
		||||
    """Serializer to map the virtual machine template instance into JSON format."""
 | 
			
		||||
    cores       = serializers.IntegerField(source='get_cores') 
 | 
			
		||||
    name        = serializers.CharField(source='get_name')
 | 
			
		||||
    disk_size   = serializers.IntegerField(source='get_disk_size')
 | 
			
		||||
    memory      = serializers.IntegerField(source='get_memory')
 | 
			
		||||
    id          = serializers.IntegerField(read_only=True)
 | 
			
		||||
    name        = serializers.CharField()
 | 
			
		||||
    cores       = serializers.IntegerField(source='template.vcpu') 
 | 
			
		||||
    disk        = serializers.IntegerField(write_only=True)
 | 
			
		||||
    disk_size   = serializers.SerializerMethodField()
 | 
			
		||||
    memory      = serializers.SerializerMethodField()
 | 
			
		||||
    core_price  = serializers.FloatField(source='template.cpu_cost')
 | 
			
		||||
    disk_size_price  = serializers.FloatField(source='template.disk_cost')
 | 
			
		||||
    memory_price  = serializers.FloatField(source='template.memory_cost')
 | 
			
		||||
    price       = serializers.SerializerMethodField()
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = VirtualMachineTemplate
 | 
			
		||||
        fields = ('id', 'name', 'cores', 'memory', 'disk_size', 'base_price', 
 | 
			
		||||
                  'core_price', 'memory_price', 'disk_size_price', 'opennebula_id')
 | 
			
		||||
        read_only_fields = ('opennebula_id', )
 | 
			
		||||
 | 
			
		||||
    def validate(self, data):
 | 
			
		||||
        # Create the opennebula model
 | 
			
		||||
        cores   = data.pop('get_cores')
 | 
			
		||||
        name    = data.pop('get_name')
 | 
			
		||||
        disk_size = data.pop('get_disk_size')
 | 
			
		||||
        memory  = data.pop('get_memory')
 | 
			
		||||
    def create(self, validated_data):
 | 
			
		||||
        data = validated_data
 | 
			
		||||
        template = data.pop('template')
 | 
			
		||||
 | 
			
		||||
        cores = template.pop('vcpu')
 | 
			
		||||
        name    = data.pop('name')
 | 
			
		||||
        disk_size = data.pop('disk') 
 | 
			
		||||
        memory  = template.pop('memory')
 | 
			
		||||
        core_price = template.pop('cpu_cost') 
 | 
			
		||||
        memory_price = template.pop('memory_cost') 
 | 
			
		||||
        disk_size_price = template.pop('disk_cost')
 | 
			
		||||
        manager = OpenNebulaManager(create_user = False)
 | 
			
		||||
        
 | 
			
		||||
        try:
 | 
			
		||||
            opennebula_id = manager.create_template(name=name, cores=cores,
 | 
			
		||||
                                                    memory=memory,
 | 
			
		||||
                                                    disk_size=disk_size)
 | 
			
		||||
            data.update({'opennebula_id':opennebula_id})
 | 
			
		||||
                                                    disk_size=disk_size,
 | 
			
		||||
                                                    core_price=core_price,
 | 
			
		||||
                                                    disk_size_price=disk_size_price,
 | 
			
		||||
                                                    memory_price=memory_price)
 | 
			
		||||
        except OpenNebulaException as err:
 | 
			
		||||
            raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
 | 
			
		||||
        
 | 
			
		||||
        return data
 | 
			
		||||
        return manager.get_template(template_id=opennebula_id)
 | 
			
		||||
 | 
			
		||||
    def create(self, validated_data):
 | 
			
		||||
        return VirtualMachineTemplate.objects.create(**validated_data)
 | 
			
		||||
    def get_disk_size(self, obj):
 | 
			
		||||
        template = obj.template
 | 
			
		||||
        disk_size = 0
 | 
			
		||||
        for disk in template.disks:
 | 
			
		||||
            disk_size += int(disk.size)
 | 
			
		||||
        return disk_size / 1024 
 | 
			
		||||
 | 
			
		||||
class TemplatePrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
 | 
			
		||||
    def display_value(self, instance):
 | 
			
		||||
        return 'Template: {}'.format(instance.get_name())
 | 
			
		||||
    def get_price(self, obj):
 | 
			
		||||
        template = obj.template
 | 
			
		||||
        price = float(template.cpu) * float(template.cpu_cost)
 | 
			
		||||
        price += (int(template.memory)/1024 * float(template.memory_cost))
 | 
			
		||||
        for disk in template.disks:
 | 
			
		||||
            price += int(disk.size)/1024 * float(template.disk_cost)
 | 
			
		||||
        return price
 | 
			
		||||
 | 
			
		||||
class VirtualMachineSerializer(serializers.ModelSerializer):
 | 
			
		||||
    def get_memory(self, obj):
 | 
			
		||||
        return int(obj.template.memory)/1024
 | 
			
		||||
 | 
			
		||||
class VirtualMachineSerializer(serializers.Serializer):
 | 
			
		||||
    """Serializer to map the virtual machine instance into JSON format."""
 | 
			
		||||
 | 
			
		||||
    #TODO: Maybe we can change to template.get_cores
 | 
			
		||||
    cores       = serializers.IntegerField(read_only=True, source='get_cores') 
 | 
			
		||||
    name        = serializers.CharField(read_only=True, source='get_name')
 | 
			
		||||
    disk_size   = serializers.IntegerField(read_only=True, source='get_disk_size')
 | 
			
		||||
    memory      = serializers.IntegerField(read_only=True, source='get_memory')
 | 
			
		||||
    #TODO: See if we can change to IPAddressField
 | 
			
		||||
    ip          = serializers.CharField(read_only=True, source='get_ip')
 | 
			
		||||
    deploy_id   = serializers.IntegerField(read_only=True, source='get_deploy_id')
 | 
			
		||||
    vm_id          = serializers.IntegerField(read_only=True, source='get_vm_id')
 | 
			
		||||
    state       = serializers.CharField(read_only=True, source='get_state')
 | 
			
		||||
    price       = serializers.FloatField(read_only=True, source='get_price')
 | 
			
		||||
    name        = serializers.CharField(read_only=True)
 | 
			
		||||
    cores       = serializers.IntegerField(read_only=True, source='template.vcpu') 
 | 
			
		||||
 | 
			
		||||
    vm_template = VirtualMachineTemplateSerializer(read_only=True)
 | 
			
		||||
    disk_size   = serializers.SerializerMethodField()
 | 
			
		||||
    memory      = serializers.SerializerMethodField()
 | 
			
		||||
    ip          = serializers.CharField(read_only=True,
 | 
			
		||||
                                        source='user_template.ungleich_public_ip',
 | 
			
		||||
                                        default='-')
 | 
			
		||||
    vm_id       = serializers.IntegerField(read_only=True, source='id')
 | 
			
		||||
    state       = serializers.CharField(read_only=True, source='str_state')
 | 
			
		||||
    price       = serializers.SerializerMethodField()
 | 
			
		||||
 | 
			
		||||
    vm_template_id = TemplatePrimaryKeyRelatedField(
 | 
			
		||||
                queryset=VirtualMachineTemplate.objects.all(),
 | 
			
		||||
                source='vm_template'
 | 
			
		||||
    template_id = serializers.ChoiceField(
 | 
			
		||||
                choices=[(key.id, key.name) for key in
 | 
			
		||||
                    OpenNebulaManager().get_templates()],
 | 
			
		||||
                source='template.template_id',
 | 
			
		||||
                write_only=True
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = VirtualMachine
 | 
			
		||||
        fields = ('id', 'opennebula_id', 'vm_template', 'vm_template_id', 'cores', 'name',
 | 
			
		||||
                'disk_size', 'memory', 'ip', 'deploy_id', 'state', 'vm_id',
 | 
			
		||||
                'price')
 | 
			
		||||
        read_only_fields = ('opennebula_id', )
 | 
			
		||||
 | 
			
		||||
    def validate(self, data):
 | 
			
		||||
        # Create the opennebula model
 | 
			
		||||
        manager = OpenNebulaManager(create_user = False)
 | 
			
		||||
    def create(self, validated_data):
 | 
			
		||||
        owner = validated_data['owner']
 | 
			
		||||
        template_id = validated_data['template']['template_id']
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            template_id = data['vm_template'].opennebula_id
 | 
			
		||||
            manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                        password=owner.password,
 | 
			
		||||
                                        create_user = True)
 | 
			
		||||
            opennebula_id = manager.create_vm(template_id)
 | 
			
		||||
            data.update({'opennebula_id':opennebula_id})
 | 
			
		||||
        except OpenNebulaException as err:
 | 
			
		||||
            raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
 | 
			
		||||
        
 | 
			
		||||
        return data
 | 
			
		||||
        return manager.get_vm(opennebula_id)
 | 
			
		||||
 | 
			
		||||
    def create(self, validated_data):
 | 
			
		||||
        return VirtualMachine.objects.create(**validated_data)
 | 
			
		||||
    def get_memory(self, obj):
 | 
			
		||||
        return int(obj.template.memory)/1024
 | 
			
		||||
 | 
			
		||||
    def get_disk_size(self, obj):
 | 
			
		||||
        template = obj.template
 | 
			
		||||
        disk_size = 0
 | 
			
		||||
        for disk in template.disks:
 | 
			
		||||
            disk_size += int(disk.size)
 | 
			
		||||
        return disk_size / 1024
 | 
			
		||||
 | 
			
		||||
    def get_price(self, obj):
 | 
			
		||||
        template = obj.template
 | 
			
		||||
        price = float(template.cpu) * float(template.cpu_cost)
 | 
			
		||||
        price += (int(template.memory)/1024 * float(template.memory_cost))
 | 
			
		||||
        for disk in template.disks:
 | 
			
		||||
            price += int(disk.size)/1024 * float(template.disk_cost)
 | 
			
		||||
        return price
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								opennebula_api/urls.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								opennebula_api/urls.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
from django.conf.urls import url, include
 | 
			
		||||
from rest_framework.urlpatterns import format_suffix_patterns
 | 
			
		||||
from .views import TemplateCreateView, TemplateDetailsView,\
 | 
			
		||||
                   VmCreateView, VmDetailsView
 | 
			
		||||
 | 
			
		||||
urlpatterns = {
 | 
			
		||||
    url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
 | 
			
		||||
 | 
			
		||||
    url(r'^templates/$', TemplateCreateView.as_view(), name="template_create"),
 | 
			
		||||
    url(r'^templates/(?P<pk>[0-9]+)/$', TemplateDetailsView.as_view(),
 | 
			
		||||
        name="templates_details"),
 | 
			
		||||
    
 | 
			
		||||
    url(r'^vms/$', VmCreateView.as_view(), name="vm_create"),
 | 
			
		||||
    url(r'^vms/(?P<pk>[0-9]+)/$', VmDetailsView.as_view(),
 | 
			
		||||
        name="vm_details"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
urlpatterns = format_suffix_patterns(urlpatterns)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,13 +1,29 @@
 | 
			
		|||
from rest_framework import generics
 | 
			
		||||
from rest_framework import permissions
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
			
		||||
from django.contrib.auth import authenticate, login
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from utils.views import LoginViewMixin
 | 
			
		||||
from membership.models import CustomUser, StripeCustomer
 | 
			
		||||
from guardian.mixins import PermissionRequiredMixin
 | 
			
		||||
 | 
			
		||||
from .serializers import VirtualMachineTemplateSerializer, \
 | 
			
		||||
                         VirtualMachineSerializer
 | 
			
		||||
from .models import VirtualMachineTemplate, VirtualMachine, OpenNebulaManager
 | 
			
		||||
from .models import OpenNebulaManager
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TemplateCreateView(generics.ListCreateAPIView):
 | 
			
		||||
    """This class defines the create behavior of our rest api."""
 | 
			
		||||
    queryset = VirtualMachineTemplate.objects.all()
 | 
			
		||||
    """This class handles the GET and POST requests."""
 | 
			
		||||
 | 
			
		||||
    serializer_class = VirtualMachineTemplateSerializer
 | 
			
		||||
    permission_classes = (permissions.IsAuthenticated, permissions.IsAdminUser)
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        manager = OpenNebulaManager()
 | 
			
		||||
        return manager.get_templates()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def perform_create(self, serializer):
 | 
			
		||||
        """Save the post data when creating a new template."""
 | 
			
		||||
| 
						 | 
				
			
			@ -16,20 +32,53 @@ class TemplateCreateView(generics.ListCreateAPIView):
 | 
			
		|||
class TemplateDetailsView(generics.RetrieveUpdateDestroyAPIView):
 | 
			
		||||
    """This class handles the http GET, PUT and DELETE requests."""
 | 
			
		||||
 | 
			
		||||
    queryset = VirtualMachineTemplate.objects.all()
 | 
			
		||||
    serializer_class = VirtualMachineTemplateSerializer
 | 
			
		||||
    permission_classes = (permissions.IsAuthenticated)
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        manager = OpenNebulaManager()
 | 
			
		||||
        return manager.get_templates()
 | 
			
		||||
 | 
			
		||||
class VmCreateView(generics.ListCreateAPIView):
 | 
			
		||||
    """This class defines the create behavior of our rest api."""
 | 
			
		||||
    queryset = VirtualMachine.objects.all()
 | 
			
		||||
    """This class handles the GET and POST requests."""
 | 
			
		||||
    serializer_class = VirtualMachineSerializer
 | 
			
		||||
    permission_classes = (permissions.IsAuthenticated, )
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                    password=owner.password,
 | 
			
		||||
                                    create_user=True)
 | 
			
		||||
        return manager.get_vms()
 | 
			
		||||
 | 
			
		||||
    def perform_create(self, serializer):
 | 
			
		||||
        """Save the post data when creating a new template."""
 | 
			
		||||
        serializer.save()
 | 
			
		||||
        serializer.save(owner=self.request.user)
 | 
			
		||||
 | 
			
		||||
class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
 | 
			
		||||
    """This class handles the http GET, PUT and DELETE requests."""
 | 
			
		||||
    permission_classes = (permissions.IsAuthenticated, )
 | 
			
		||||
 | 
			
		||||
    queryset = VirtualMachine.objects.all()
 | 
			
		||||
    serializer_class = VirtualMachineSerializer
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                    password=owner.password,
 | 
			
		||||
                                    create_user=True)
 | 
			
		||||
        return manager.get_vms()
 | 
			
		||||
 | 
			
		||||
    def get_object(self):
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                    password=owner.password,
 | 
			
		||||
                                    create_user=True)
 | 
			
		||||
        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)
 | 
			
		||||
        manager.delete_vm(instance.id)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue