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()),
 | 
					urlpatterns = [   url(r'^index.html$', LandingView.as_view()),
 | 
				
			||||||
                  url(r'^hosting/', include('hosting.urls', namespace="hosting")),
 | 
					                  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'^railshosting/', RailsHostingView.as_view(), name="rails.hosting"),
 | 
				
			||||||
                  url(r'^nodehosting/', NodeJSHostingView.as_view(), name="node.hosting"),
 | 
					                  url(r'^nodehosting/', NodeJSHostingView.as_view(), name="node.hosting"),
 | 
				
			||||||
                  url(r'^djangohosting/', DjangoHostingView.as_view(), name="django.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 utils.mailer import BaseEmail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .forms import HostingOrderAdminForm
 | 
					from .models import HostingOrder, HostingBill
 | 
				
			||||||
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, \
 | 
					 | 
				
			||||||
                    ManageVM, HostingBill
 | 
					 | 
				
			||||||
from .opennebula_functions import HostingManageVMAdmin
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HostingOrderAdmin(admin.ModelAdmin):
 | 
					admin.site.register(HostingOrder)
 | 
				
			||||||
    # 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(HostingBill)
 | 
					admin.site.register(HostingBill)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,39 +7,7 @@ from django.contrib.auth import authenticate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from utils.stripe_utils import StripeUtils
 | 
					from utils.stripe_utils import StripeUtils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import HostingOrder, VirtualMachinePlan, UserHostingKey
 | 
					from .models import HostingOrder, 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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HostingUserLoginForm(forms.Form):
 | 
					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.shortcuts import redirect
 | 
				
			||||||
from django.core.urlresolvers import reverse
 | 
					from django.core.urlresolvers import reverse
 | 
				
			||||||
from .models import VirtualMachinePlan, VirtualMachineType
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProcessVMSelectionMixin(object):
 | 
					class ProcessVMSelectionMixin(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post(self, request, *args, **kwargs):
 | 
					    def post(self, request, *args, **kwargs):
 | 
				
			||||||
        configuration = request.POST.get('configuration')
 | 
					        #configuration = request.POST.get('configuration')
 | 
				
			||||||
        configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
 | 
					        #configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
 | 
				
			||||||
        vm_template = request.POST.get('vm_template')
 | 
					        vm_template_id = request.POST.get('vm_template_id')
 | 
				
			||||||
        vm_type = VirtualMachineType.objects.get(id=vm_template)
 | 
					 | 
				
			||||||
        vm_specs = vm_type.get_specs()
 | 
					 | 
				
			||||||
        vm_specs.update({
 | 
					        vm_specs.update({
 | 
				
			||||||
            'configuration_display': configuration_display,
 | 
					            'configuration_display': configuration_display,
 | 
				
			||||||
            'configuration': configuration,
 | 
					            'configuration': configuration,
 | 
				
			||||||
            'final_price': vm_type.final_price,
 | 
					            'vm_template_id': vm_template_id
 | 
				
			||||||
            'vm_template': vm_template
 | 
					 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        # 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
 | 
					        request.session['vm_specs'] = vm_specs
 | 
				
			||||||
        if not request.user.is_authenticated():
 | 
					        if not request.user.is_authenticated():
 | 
				
			||||||
            request.session['vm_specs'] = vm_specs
 | 
					 | 
				
			||||||
            request.session['next'] = reverse('hosting:payment')
 | 
					            request.session['next'] = reverse('hosting:payment')
 | 
				
			||||||
            return redirect(reverse('hosting:login'))
 | 
					            return redirect(reverse('hosting:login'))
 | 
				
			||||||
        return redirect(reverse('hosting:payment'))
 | 
					        return redirect(reverse('hosting:payment'))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import socket
 | 
					import socket
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import oca
 | 
					import oca
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
| 
						 | 
					@ -19,252 +21,15 @@ from .managers import VMPlansManager
 | 
				
			||||||
from oca.exceptions import OpenNebulaException
 | 
					from oca.exceptions import OpenNebulaException
 | 
				
			||||||
from oca.pool import WrongNameError
 | 
					from oca.pool import WrongNameError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
logger = logging.getLogger(__name__)
 | 
					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):
 | 
					class HostingOrder(AssignPermissionsMixin, models.Model):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ORDER_APPROVED_STATUS = 'Approved'
 | 
					    ORDER_APPROVED_STATUS = 'Approved'
 | 
				
			||||||
    ORDER_DECLINED_STATUS = 'Declined'
 | 
					    ORDER_DECLINED_STATUS = 'Declined'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vm_plan = models.ForeignKey(VirtualMachinePlan, related_name='hosting_orders')
 | 
					    vm_id = models.IntegerField(default=0)
 | 
				
			||||||
    customer = models.ForeignKey(StripeCustomer)
 | 
					    customer = models.ForeignKey(StripeCustomer)
 | 
				
			||||||
    billing_address = models.ForeignKey(BillingAddress)
 | 
					    billing_address = models.ForeignKey(BillingAddress)
 | 
				
			||||||
    created_at = models.DateTimeField(auto_now_add=True)
 | 
					    created_at = models.DateTimeField(auto_now_add=True)
 | 
				
			||||||
| 
						 | 
					@ -272,6 +37,7 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
 | 
				
			||||||
    last4 = models.CharField(max_length=4)
 | 
					    last4 = models.CharField(max_length=4)
 | 
				
			||||||
    cc_brand = models.CharField(max_length=10)
 | 
					    cc_brand = models.CharField(max_length=10)
 | 
				
			||||||
    stripe_charge_id = models.CharField(max_length=100, null=True)
 | 
					    stripe_charge_id = models.CharField(max_length=100, null=True)
 | 
				
			||||||
 | 
					    price = models.FloatField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    permissions = ('view_hostingorder',)
 | 
					    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
 | 
					        return self.ORDER_APPROVED_STATUS if self.approved else self.ORDER_DECLINED_STATUS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def create(cls, vm_plan=None, customer=None, billing_address=None):
 | 
					    def create(cls, price=None, vm_id=None, customer=None, billing_address=None):
 | 
				
			||||||
        instance = cls.objects.create(vm_plan=vm_plan, customer=customer,
 | 
					        instance = cls.objects.create(
 | 
				
			||||||
                                      billing_address=billing_address)
 | 
					            price=price,
 | 
				
			||||||
 | 
					            vm_id=vm_id,
 | 
				
			||||||
 | 
					            customer=customer,
 | 
				
			||||||
 | 
					            billing_address=billing_address
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        instance.assign_permissions(customer.user)
 | 
					        instance.assign_permissions(customer.user)
 | 
				
			||||||
        return instance
 | 
					        return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -336,17 +106,6 @@ class UserHostingKey(models.Model):
 | 
				
			||||||
        # self.save(update_fields=['public_key'])
 | 
					        # self.save(update_fields=['public_key'])
 | 
				
			||||||
        return private_key, 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):
 | 
					class HostingBill(AssignPermissionsMixin, models.Model):
 | 
				
			||||||
    customer = models.ForeignKey(StripeCustomer)
 | 
					    customer = models.ForeignKey(StripeCustomer)
 | 
				
			||||||
    billing_address = models.ForeignKey(BillingAddress)
 | 
					    billing_address = models.ForeignKey(BillingAddress)
 | 
				
			||||||
| 
						 | 
					@ -367,32 +126,3 @@ class HostingBill(AssignPermissionsMixin, models.Model):
 | 
				
			||||||
        instance = cls.objects.create(customer=customer, billing_address=billing_address)
 | 
					        instance = cls.objects.create(customer=customer, billing_address=billing_address)
 | 
				
			||||||
        return instance
 | 
					        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>
 | 
				
			||||||
            <div class="row">
 | 
					            <div class="row">
 | 
				
			||||||
                <div class="col-sm-6">
 | 
					                <div class="col-sm-6">
 | 
				
			||||||
                    {% trans "CH02 ............" %}
 | 
					                    {% trans "CH02 0900 0000 6071 8848 8%}
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="col-sm-6">
 | 
					                <div class="col-sm-6">
 | 
				
			||||||
                    {% trans "POFICHBEXXX" %}
 | 
					                    {% trans "POFICHBEXXX" %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,15 +12,19 @@
 | 
				
			||||||
                    {% csrf_token %}
 | 
					                    {% csrf_token %}
 | 
				
			||||||
                    <div class="form-group">
 | 
					                    <div class="form-group">
 | 
				
			||||||
                        Select VM:
 | 
					                        Select VM:
 | 
				
			||||||
                        <select name="vm_template">
 | 
					                        <select name="vm_template_id">
 | 
				
			||||||
                            {% for vm in vm_types %}
 | 
					                            {% 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 %}
 | 
					                            {% endfor %}
 | 
				
			||||||
                        </select>
 | 
					                        </select>
 | 
				
			||||||
                    </div> 
 | 
					                    </div> 
 | 
				
			||||||
                    <div class="form-group">
 | 
					<!--                     <div class="form-group">
 | 
				
			||||||
                        Select VM Configuration:
 | 
					                        Select VM Configuration:
 | 
				
			||||||
                        <select name="configuration">
 | 
					                        <select name="configuration">
 | 
				
			||||||
                            {% for config in configuration_options %}
 | 
					                            {% for config in configuration_options %}
 | 
				
			||||||
| 
						 | 
					@ -29,7 +33,7 @@
 | 
				
			||||||
                                
 | 
					                                
 | 
				
			||||||
                            {% endfor %}
 | 
					                            {% endfor %}
 | 
				
			||||||
                        </select>
 | 
					                        </select>
 | 
				
			||||||
                    </div>                          
 | 
					                    </div>  -->                         
 | 
				
			||||||
                    <div class="form-group">
 | 
					                    <div class="form-group">
 | 
				
			||||||
                        <button class="btn btn-success" >{% trans "Start VM"%} </button>                         
 | 
					                        <button class="btn btn-success" >{% trans "Start VM"%} </button>                         
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
| 
						 | 
					@ -42,4 +46,4 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{%endblock%}
 | 
					{%endblock%}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,17 +49,13 @@
 | 
				
			||||||
            <h3><b>{% trans "Order summary"%}</b></h3>
 | 
					            <h3><b>{% trans "Order summary"%}</b></h3>
 | 
				
			||||||
            <hr>
 | 
					            <hr>
 | 
				
			||||||
            <div class="content">
 | 
					            <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>
 | 
					                <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>
 | 
					                <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>
 | 
					                <hr>
 | 
				
			||||||
                <p><b>{% trans "Memory"%}</b> <span class="pull-right">{{order.vm_plan.memory}} GiB</span></p>
 | 
					                <h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4>
 | 
				
			||||||
                <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>
 | 
					 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <br/>
 | 
					            <br/>
 | 
				
			||||||
            {% url 'hosting:payment' as payment_url %}
 | 
					            {% url 'hosting:payment' as payment_url %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,15 +100,14 @@
 | 
				
			||||||
							<div class="content">
 | 
												<div class="content">
 | 
				
			||||||
								<!-- <p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.location_code}}</span></p> -->
 | 
													<!-- <p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.location_code}}</span></p> -->
 | 
				
			||||||
								<!-- <hr> -->
 | 
													<!-- <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>
 | 
													<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>
 | 
					 | 
				
			||||||
								<hr>
 | 
													<hr>
 | 
				
			||||||
								<p><b>Disk space</b> <span class="pull-right">{{request.session.vm_specs.disk_size}} GiB</span></p>
 | 
													<p><b>Disk space</b> <span class="pull-right">{{request.session.template.disk_size}} GiB</span></p>
 | 
				
			||||||
								<hr>
 | 
													<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>
 | 
											</div>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,12 +25,6 @@
 | 
				
			||||||
				            		{% trans "Billing"%}
 | 
									            		{% trans "Billing"%}
 | 
				
			||||||
				            	</a>
 | 
									            	</a>
 | 
				
			||||||
				            </li>
 | 
									            </li>
 | 
				
			||||||
				            <li>
 | 
					 | 
				
			||||||
				            	<a href="#orders-v" data-toggle="tab">
 | 
					 | 
				
			||||||
				            		<i class="fa fa-credit-card"></i> 
 | 
					 | 
				
			||||||
				            		{% trans "Orders"%}
 | 
					 | 
				
			||||||
				            	</a>
 | 
					 | 
				
			||||||
				            </li>
 | 
					 | 
				
			||||||
				            <li>
 | 
									            <li>
 | 
				
			||||||
				            	<a href="#status-v" data-toggle="tab">
 | 
									            	<a href="#status-v" data-toggle="tab">
 | 
				
			||||||
				            		<i class="fa fa-signal" aria-hidden="true"></i> {% trans "Status"%}
 | 
									            		<i class="fa fa-signal" aria-hidden="true"></i> {% trans "Status"%}
 | 
				
			||||||
| 
						 | 
					@ -109,56 +103,22 @@
 | 
				
			||||||
									</div>
 | 
														</div>
 | 
				
			||||||
				            	</div>
 | 
									            	</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="tab-pane" id="status-v">
 | 
				
			||||||
				            	<div class="row ">
 | 
									            	<div class="row ">
 | 
				
			||||||
									<div class="col-md-12 inline-headers">
 | 
														<div class="col-md-12 inline-headers">
 | 
				
			||||||
										<h3>{% trans "Current status"%}</h3>
 | 
															<h3>{% trans "Current status"%}</h3>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
										<div  class="pull-right space-above">
 | 
															<div  class="pull-right space-above">
 | 
				
			||||||
                                            {% if virtual_machine.state == 'ACTIVE' %}
 | 
																{% if virtual_machine.state == 'PENDING' %}
 | 
				
			||||||
                                                <span class="h3 label label-success"><strong> {{virtual_machine.state}}</strong></span>
 | 
																	<span class="label
 | 
				
			||||||
                                            {% elif  virtual_machine.state == 'POWEROFF' %}
 | 
					                                                    label-warning"><strong>Pending</strong></span>
 | 
				
			||||||
                                                <span class="h3 label label-danger"><strong>{{virtual_machine.state}}</strong></span>
 | 
																{% elif  virtual_machine.state == 'ACTIVE' %}
 | 
				
			||||||
                                            {% else %}
 | 
																	<span class="label
 | 
				
			||||||
                                                <span class="h3 label label-warning"><strong>{{virtual_machine.state}}</strong></span>
 | 
					                                                    label-success"><strong>Online</strong></span>
 | 
				
			||||||
                                            {% endif %}  
 | 
																{% elif  virtual_machine.state == 'FAILED'%}
 | 
				
			||||||
 | 
																	<span class="label
 | 
				
			||||||
 | 
					                                                    label-danger"><strong>Failed</strong></span>
 | 
				
			||||||
 | 
																{% endif %}
 | 
				
			||||||
										</div>
 | 
															</div>
 | 
				
			||||||
									</div>
 | 
														</div>
 | 
				
			||||||
				            	</div>
 | 
									            	</div>
 | 
				
			||||||
| 
						 | 
					@ -166,11 +126,12 @@
 | 
				
			||||||
				            	<div class="row">
 | 
									            	<div class="row">
 | 
				
			||||||
									<div class="col-md-12 space-above-big">
 | 
														<div class="col-md-12 space-above-big">
 | 
				
			||||||
										<div class="pull-right">
 | 
															<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 %} 
 | 
																{% csrf_token %} 
 | 
				
			||||||
											</form>	
 | 
																</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>
 | 
															</div>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -194,7 +155,7 @@
 | 
				
			||||||
									                {% trans "Terminate your Virtual Machine"%}
 | 
														                {% trans "Terminate your Virtual Machine"%}
 | 
				
			||||||
									            </div>
 | 
														            </div>
 | 
				
			||||||
									            <div class="modal-body">
 | 
														            <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>
 | 
				
			||||||
									            <div class="modal-footer">
 | 
														            <div class="modal-footer">
 | 
				
			||||||
									                <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Cancel"%}</button>
 | 
														                <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Cancel"%}</button>
 | 
				
			||||||
| 
						 | 
					@ -220,12 +181,3 @@
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{%endblock%}
 | 
					{%endblock%}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,15 +30,15 @@
 | 
				
			||||||
				</tr>
 | 
									</tr>
 | 
				
			||||||
				</thead>
 | 
									</thead>
 | 
				
			||||||
				<tbody> 
 | 
									<tbody> 
 | 
				
			||||||
					{% for vm in vms_opennebula %}
 | 
										{% for vm in vms %}
 | 
				
			||||||
					<tr>
 | 
										<tr>
 | 
				
			||||||
						<td scope="row">{{vm.name}}</td> 
 | 
											<td scope="row">{{vm.vm_id}}</td> 
 | 
				
			||||||
						<td>{{vm.price|floatformat:2}} CHF</td> 
 | 
											<td>{{vm.price}} CHF</td> 
 | 
				
			||||||
						<td>
 | 
											<td>
 | 
				
			||||||
                           
 | 
					                           
 | 
				
			||||||
							{% if vm.state == 'ACTIVE' %}
 | 
												{% if vm.state == 'ACTIVE' %}
 | 
				
			||||||
								<span class="h3 label label-success"><strong> {{vm.state}}</strong></span>
 | 
													<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>
 | 
													<span class="h3 label label-danger"><strong>{{vm.state}}</strong></span>
 | 
				
			||||||
							{% else %}
 | 
												{% else %}
 | 
				
			||||||
								<span class="h3 label label-warning"><strong>{{vm.state}}</strong></span>
 | 
													<span class="h3 label label-warning"><strong>{{vm.state}}</strong></span>
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						</td> 
 | 
											</td> 
 | 
				
			||||||
						<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>
 | 
					                        </td>
 | 
				
			||||||
					</tr>
 | 
										</tr>
 | 
				
			||||||
					{% endfor %}
 | 
										{% endfor %}
 | 
				
			||||||
| 
						 | 
					@ -76,4 +77,4 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{%endblock%}
 | 
					{%endblock%}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										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 stored_messages.api import mark_read
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
from membership.models import CustomUser, StripeCustomer
 | 
					from membership.models import CustomUser, StripeCustomer
 | 
				
			||||||
from utils.stripe_utils import StripeUtils
 | 
					from utils.stripe_utils import StripeUtils
 | 
				
			||||||
from utils.forms import BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm
 | 
					from utils.forms import BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm
 | 
				
			||||||
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
 | 
					from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
 | 
				
			||||||
from utils.mailer import BaseEmail
 | 
					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 .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyForm
 | 
				
			||||||
from .mixins import ProcessVMSelectionMixin
 | 
					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.exceptions import OpenNebulaException
 | 
				
			||||||
from oca.pool import WrongNameError
 | 
					from oca.pool import WrongNameError
 | 
				
			||||||
| 
						 | 
					@ -387,57 +389,26 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            context = self.get_context_data()
 | 
					            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)
 | 
					            final_price = specifications.get('price', 1)
 | 
				
			||||||
 | 
					 | 
				
			||||||
            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)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            token = form.cleaned_data.get('token')
 | 
					            token = form.cleaned_data.get('token')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            owner = self.request.user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Get or create stripe customer
 | 
					            # 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)
 | 
					                                                    token=token)
 | 
				
			||||||
            if not customer:
 | 
					            if not customer:
 | 
				
			||||||
                form.add_error("__all__", "Invalid credit card")
 | 
					                form.add_error("__all__", "Invalid credit card")
 | 
				
			||||||
                return self.render_to_response(self.get_context_data(form=form))
 | 
					                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
 | 
					            # Create Billing Address
 | 
				
			||||||
            billing_address = form.save()
 | 
					            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
 | 
					            # Make stripe charge to a customer
 | 
				
			||||||
            stripe_utils = StripeUtils()
 | 
					            stripe_utils = StripeUtils()
 | 
				
			||||||
            charge_response = stripe_utils.make_charge(amount=final_price,
 | 
					            charge_response = stripe_utils.make_charge(amount=final_price,
 | 
				
			||||||
| 
						 | 
					@ -454,11 +425,11 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            charge = charge_response.get('response_object')
 | 
					            charge = charge_response.get('response_object')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Associate an order with a stripe payment
 | 
					            # Create OpenNebulaManager
 | 
				
			||||||
            order.set_stripe_charge(charge)
 | 
					            manager = OpenNebulaManager(email=owner.email,
 | 
				
			||||||
 | 
					                                        password=owner.password,
 | 
				
			||||||
            # If the Stripe payment was successed, set order status approved
 | 
					                                        create_user=True)
 | 
				
			||||||
            order.set_approved()
 | 
					            template = manager.get_template(vm_template_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Get user ssh key
 | 
					            # Get user ssh key
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
| 
						 | 
					@ -466,26 +437,46 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
				
			||||||
                    user=self.request.user
 | 
					                    user=self.request.user
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # Add ssh_key to specs
 | 
					 | 
				
			||||||
                specs.update({
 | 
					 | 
				
			||||||
                    'ssh_key': user_key.public_key
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            except UserHostingKey.DoesNotExist:
 | 
					            except UserHostingKey.DoesNotExist:
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Create a vm using logged user
 | 
					            # Create a vm using logged user
 | 
				
			||||||
            opennebula_vm_id = VirtualMachinePlan.create_opennebula_vm(
 | 
					            vm_id = manager.create_vm(
 | 
				
			||||||
                self.request.user,
 | 
					                vm_template_id,
 | 
				
			||||||
                specs
 | 
					                ssh_key=user_key.public_key
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            plan.opennebula_id = opennebula_vm_id
 | 
					            # Create a Hosting Order
 | 
				
			||||||
            plan.save()
 | 
					            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
 | 
					            # Send notification to ungleich as soon as VM has been booked
 | 
				
			||||||
            context = {
 | 
					            context = {
 | 
				
			||||||
                'vm': plan,
 | 
					                'vm': vm,
 | 
				
			||||||
                'order': order,
 | 
					                'order': order,
 | 
				
			||||||
                'base_url': "{0}://{1}".format(request.scheme, request.get_host())
 | 
					                'base_url': "{0}://{1}".format(request.scheme, request.get_host())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -512,6 +503,18 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai
 | 
				
			||||||
    permission_required = ['view_hostingorder']
 | 
					    permission_required = ['view_hostingorder']
 | 
				
			||||||
    model = 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):
 | 
					class OrdersHostingListView(LoginRequiredMixin, ListView):
 | 
				
			||||||
    template_name = "hosting/orders.html"
 | 
					    template_name = "hosting/orders.html"
 | 
				
			||||||
| 
						 | 
					@ -537,24 +540,17 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView):
 | 
				
			||||||
    template_name = "hosting/virtual_machines.html"
 | 
					    template_name = "hosting/virtual_machines.html"
 | 
				
			||||||
    login_url = reverse_lazy('hosting:login')
 | 
					    login_url = reverse_lazy('hosting:login')
 | 
				
			||||||
    context_object_name = "vms"
 | 
					    context_object_name = "vms"
 | 
				
			||||||
    model = VirtualMachinePlan
 | 
					 | 
				
			||||||
    paginate_by = 10
 | 
					    paginate_by = 10
 | 
				
			||||||
    ordering = '-id'
 | 
					    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):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        # hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin)
 | 
					        owner = self.request.user
 | 
				
			||||||
        # print(hosting_admin.show_vms_view(self.request))
 | 
					        manager = OpenNebulaManager(email=owner.email,
 | 
				
			||||||
        # print(VirtualMachinePlan.get_vms(self.request.user.))
 | 
					                                    password=owner.password,
 | 
				
			||||||
        user = self.request.user
 | 
					                                    create_user=True)
 | 
				
			||||||
        self.queryset = VirtualMachinePlan.objects.active(user)
 | 
					        queryset = manager.get_vms()
 | 
				
			||||||
        return super(VirtualMachinesPlanListView, self).get_queryset()
 | 
					        serializer = VirtualMachineSerializer(queryset, many=True)
 | 
				
			||||||
 | 
					        return serializer.data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CreateVirtualMachinesView(LoginRequiredMixin, View):
 | 
					class CreateVirtualMachinesView(LoginRequiredMixin, View):
 | 
				
			||||||
| 
						 | 
					@ -574,107 +570,70 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            return HttpResponseRedirect(reverse('hosting:key_pair'))
 | 
					            return HttpResponseRedirect(reverse('hosting:key_pair'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #TODO: Replace with OpenNebulaManager.get_apps
 | 
				
			||||||
 | 
					        templates = OpenNebulaManager().get_templates()
 | 
				
			||||||
 | 
					        data = VirtualMachineTemplateSerializer(templates, many=True).data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        context = {
 | 
					        context = {
 | 
				
			||||||
            'vm_types': VirtualMachineType.get_serialized_vm_types(),
 | 
					            'templates': data,
 | 
				
			||||||
            'configuration_options': VirtualMachinePlan.VM_CONFIGURATION
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        # context = {}
 | 
					        # context = {}
 | 
				
			||||||
        return render(request, self.template_name, context)
 | 
					        return render(request, self.template_name, context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post(self, request):
 | 
					    def post(self, request):
 | 
				
			||||||
        configuration = request.POST.get('configuration')
 | 
					        template_id = int(request.POST.get('vm_template_id'))
 | 
				
			||||||
        configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
 | 
					        template = OpenNebulaManager().get_template(template_id)
 | 
				
			||||||
        vm_template = request.POST.get('vm_template')
 | 
					        data = VirtualMachineTemplateSerializer(template).data
 | 
				
			||||||
        vm_type = VirtualMachineType.objects.get(id=vm_template)
 | 
					        request.session['template'] = data
 | 
				
			||||||
        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
 | 
					 | 
				
			||||||
        return redirect(reverse('hosting:payment'))
 | 
					        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(LoginRequiredMixin, View):
 | 
				
			||||||
class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
 | 
					 | 
				
			||||||
    template_name = "hosting/virtual_machine_detail.html"
 | 
					    template_name = "hosting/virtual_machine_detail.html"
 | 
				
			||||||
    login_url = reverse_lazy('hosting:login')
 | 
					    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):
 | 
					    def get_object(self):
 | 
				
			||||||
        opennebula_vm_id = self.kwargs.get('pk')
 | 
					        owner = self.request.user
 | 
				
			||||||
        opennebula_vm = None
 | 
					        vm = None
 | 
				
			||||||
 | 
					        manager = OpenNebulaManager(
 | 
				
			||||||
 | 
					            email=owner.email,
 | 
				
			||||||
 | 
					            password=owner.password,
 | 
				
			||||||
 | 
					            create_user=True
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        vm_id = self.kwargs.get('pk')
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            opennebula_vm = VirtualMachinePlan.objects.get(opennebula_id=opennebula_vm_id)
 | 
					            vm = manager.get_vm(vm_id)
 | 
				
			||||||
        except Exception as error:
 | 
					        except Exception as error:
 | 
				
			||||||
            print(error)
 | 
					            print(error)
 | 
				
			||||||
            raise Http404()
 | 
					            raise Http404()
 | 
				
			||||||
        return opennebula_vm
 | 
					        return vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_success_url(self):
 | 
					    def get_success_url(self):
 | 
				
			||||||
        final_url = reverse('hosting:virtual_machines')
 | 
					        final_url = reverse('hosting:virtual_machines')
 | 
				
			||||||
        return final_url
 | 
					        return final_url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        opennebula_vm_id = self.kwargs.get('pk')
 | 
					        vm = self.get_object()
 | 
				
			||||||
        try:
 | 
					        serializer = VirtualMachineSerializer(vm)
 | 
				
			||||||
            opennebula_vm = VirtualMachinePlan.get_vm(
 | 
					 | 
				
			||||||
                self.request.user,
 | 
					 | 
				
			||||||
                opennebula_vm_id
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        except Exception as error:
 | 
					 | 
				
			||||||
            print(error)
 | 
					 | 
				
			||||||
            raise Http404()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        context = {
 | 
					        context = {
 | 
				
			||||||
            'virtual_machine': opennebula_vm,
 | 
					            'virtual_machine': serializer.data,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        # context = {}
 | 
					 | 
				
			||||||
        return render(request, self.template_name, context)
 | 
					        return render(request, self.template_name, context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post(self, request, *args, **kwargs):
 | 
					    def post(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        owner = self.request.user
 | 
				
			||||||
        vm = self.get_object()
 | 
					        vm = self.get_object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        opennebula_vm_id = self.kwargs.get('pk')
 | 
					        opennebula_vm_id = self.kwargs.get('pk')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        terminated = VirtualMachinePlan.terminate_opennebula_vm(
 | 
					        manager = OpenNebulaManager(
 | 
				
			||||||
            self.request.user,
 | 
					            email=owner.email,
 | 
				
			||||||
            opennebula_vm_id
 | 
					            password=owner.password,
 | 
				
			||||||
 | 
					            create_user=True
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        terminated = manager.delete_vm(
 | 
				
			||||||
 | 
					            vm.id
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not terminated:
 | 
					        if not terminated:
 | 
				
			||||||
| 
						 | 
					@ -684,8 +643,6 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            return HttpResponseRedirect(self.get_success_url())
 | 
					            return HttpResponseRedirect(self.get_success_url())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #vm.cancel_plan()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        context = {
 | 
					        context = {
 | 
				
			||||||
            'vm': vm,
 | 
					            'vm': vm,
 | 
				
			||||||
            'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
 | 
					            '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):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        # Get context
 | 
					        # Get context
 | 
				
			||||||
        context = super(DetailView, self).get_context_data(**kwargs)
 | 
					        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
 | 
					        # Get vms
 | 
				
			||||||
        try:
 | 
					        queryset = manager.get_vms()
 | 
				
			||||||
            context['vms'] = self.get_object().get_vms()
 | 
					        vms = VirtualMachineSerializer(queryset, many=True).data
 | 
				
			||||||
        except:
 | 
					        context['vms'] = vms
 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return context
 | 
					        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 oca
 | 
				
			||||||
import socket
 | 
					import socket
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.db import models
 | 
					 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					from django.utils.functional import cached_property
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from oca.pool import WrongNameError
 | 
					from oca.pool import WrongNameError
 | 
				
			||||||
 | 
					from oca.exceptions import OpenNebulaException
 | 
				
			||||||
class VirtualMachineTemplate(models.Model):
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
    """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()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OpenNebulaManager():
 | 
					class OpenNebulaManager():
 | 
				
			||||||
    """This class represents an opennebula manager."""
 | 
					    """This class represents an opennebula manager."""
 | 
				
			||||||
| 
						 | 
					@ -175,8 +79,13 @@ class OpenNebulaManager():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _get_vm_pool(self):
 | 
					    def _get_vm_pool(self):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
           vm_pool = oca.VirtualMachinePool(self.oneadmin_client)
 | 
					            vm_pool = oca.VirtualMachinePool(self.client)
 | 
				
			||||||
           vm_pool.info()
 | 
					            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
 | 
					        #TODO: Replace with logger
 | 
				
			||||||
        except ConnectionRefusedError:
 | 
					        except ConnectionRefusedError:
 | 
				
			||||||
            print('Could not connect to host: {host} via protocol {protocol}'.format(
 | 
					            print('Could not connect to host: {host} via protocol {protocol}'.format(
 | 
				
			||||||
| 
						 | 
					@ -186,19 +95,25 @@ class OpenNebulaManager():
 | 
				
			||||||
            raise ConnectionRefusedError
 | 
					            raise ConnectionRefusedError
 | 
				
			||||||
        return vm_pool
 | 
					        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()
 | 
					        vm_pool = self._get_vm_pool()
 | 
				
			||||||
        # Get virtual machines from all users 
 | 
					        return vm_pool.get_by_id(int(vm_id))
 | 
				
			||||||
        vm_pool.info(filter=-2)
 | 
					 | 
				
			||||||
        return vm_pool.get_by_id(vm_id)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_vm(self, template_id):
 | 
					    #TODO: get app with id 
 | 
				
			||||||
        template_pool = self._get_template_pool()
 | 
					    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(
 | 
				
			||||||
        template = template_pool.get_by_id(template_id)
 | 
					            ssh_key=ssh_key
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        vm_id = template.instantiate()
 | 
					        vm_id = self.oneadmin_client.call(
 | 
				
			||||||
 | 
					            oca.VmTemplate.METHODS['instantiate'],
 | 
				
			||||||
 | 
					            template_id,
 | 
				
			||||||
 | 
					            '',
 | 
				
			||||||
 | 
					            False,
 | 
				
			||||||
 | 
					            extra_template
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.oneadmin_client.call(
 | 
					            self.oneadmin_client.call(
 | 
				
			||||||
                oca.VirtualMachine.METHODS['chown'],
 | 
					                oca.VirtualMachine.METHODS['chown'],
 | 
				
			||||||
| 
						 | 
					@ -207,12 +122,33 @@ class OpenNebulaManager():
 | 
				
			||||||
                self.opennebula_user.group_ids[0]
 | 
					                self.opennebula_user.group_ids[0]
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        except AttributeError:
 | 
					        except AttributeError:
 | 
				
			||||||
            pass
 | 
					            print('Could not change owner, opennebula_user is not set.')
 | 
				
			||||||
        return vm_id
 | 
					        return vm_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delete_vm(self, vm_id):
 | 
					    def delete_vm(self, vm_id):
 | 
				
			||||||
        vm = self._get_vm(vm_id)
 | 
					        TERMINATE_ACTION = 'terminate'
 | 
				
			||||||
        vm.delete()
 | 
					        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):
 | 
					    def _get_template_pool(self):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
| 
						 | 
					@ -227,19 +163,31 @@ class OpenNebulaManager():
 | 
				
			||||||
            raise ConnectionRefusedError
 | 
					            raise ConnectionRefusedError
 | 
				
			||||||
        return template_pool
 | 
					        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()
 | 
					        template_pool = self._get_template_pool()
 | 
				
			||||||
        return template_pool.get_by_id(template_id)
 | 
					        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.
 | 
					        """Create and add a new template to opennebula.
 | 
				
			||||||
        :param name:      A string representation describing the template.
 | 
					        :param name:      A string representation describing the template.
 | 
				
			||||||
                          Used as label in view.
 | 
					                          Used as label in view.
 | 
				
			||||||
        :param cores:     Amount of virtual cpu cores for the VM.
 | 
					        :param cores:     Amount of virtual cpu cores for the VM.
 | 
				
			||||||
        :param memory:    Amount of RAM for the VM (MB)
 | 
					        :param memory:  Amount of RAM for the VM (GB)
 | 
				
			||||||
        :param disk_size: Amount of disk space for VM (MB)
 | 
					        :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>
 | 
					        template_string_formatter = """<TEMPLATE>
 | 
				
			||||||
                                        <NAME>{name}</NAME>
 | 
					                                        <NAME>{name}</NAME>
 | 
				
			||||||
| 
						 | 
					@ -251,6 +199,10 @@ class OpenNebulaManager():
 | 
				
			||||||
                                         <SIZE>{size}</SIZE>
 | 
					                                         <SIZE>{size}</SIZE>
 | 
				
			||||||
                                         <DEV_PREFIX>vd</DEV_PREFIX>
 | 
					                                         <DEV_PREFIX>vd</DEV_PREFIX>
 | 
				
			||||||
                                        </DISK>
 | 
					                                        </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>
 | 
				
			||||||
                                       """
 | 
					                                       """
 | 
				
			||||||
        template_id = oca.VmTemplate.allocate(
 | 
					        template_id = oca.VmTemplate.allocate(
 | 
				
			||||||
| 
						 | 
					@ -260,7 +212,12 @@ class OpenNebulaManager():
 | 
				
			||||||
                vcpu=cores,
 | 
					                vcpu=cores,
 | 
				
			||||||
                cpu=0.1*cores,
 | 
					                cpu=0.1*cores,
 | 
				
			||||||
                size=1024 * disk_size,
 | 
					                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):
 | 
					    def delete_template(self, template_id):
 | 
				
			||||||
        self.oneadmin_client.call(oca.VmTemplate.METHODS['delete'], template_id, False)
 | 
					        self.oneadmin_client.call(oca.VmTemplate.METHODS['delete'], template_id, False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,91 +3,117 @@ import oca
 | 
				
			||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from oca import OpenNebulaException
 | 
					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."""
 | 
					    """Serializer to map the virtual machine template instance into JSON format."""
 | 
				
			||||||
    cores       = serializers.IntegerField(source='get_cores') 
 | 
					    id          = serializers.IntegerField(read_only=True)
 | 
				
			||||||
    name        = serializers.CharField(source='get_name')
 | 
					    name        = serializers.CharField()
 | 
				
			||||||
    disk_size   = serializers.IntegerField(source='get_disk_size')
 | 
					    cores       = serializers.IntegerField(source='template.vcpu') 
 | 
				
			||||||
    memory      = serializers.IntegerField(source='get_memory')
 | 
					    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:
 | 
					    def create(self, validated_data):
 | 
				
			||||||
        model = VirtualMachineTemplate
 | 
					        data = validated_data
 | 
				
			||||||
        fields = ('id', 'name', 'cores', 'memory', 'disk_size', 'base_price', 
 | 
					        template = data.pop('template')
 | 
				
			||||||
                  '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')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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)
 | 
					        manager = OpenNebulaManager(create_user = False)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            opennebula_id = manager.create_template(name=name, cores=cores,
 | 
					            opennebula_id = manager.create_template(name=name, cores=cores,
 | 
				
			||||||
                                                    memory=memory,
 | 
					                                                    memory=memory,
 | 
				
			||||||
                                                    disk_size=disk_size)
 | 
					                                                    disk_size=disk_size,
 | 
				
			||||||
            data.update({'opennebula_id':opennebula_id})
 | 
					                                                    core_price=core_price,
 | 
				
			||||||
 | 
					                                                    disk_size_price=disk_size_price,
 | 
				
			||||||
 | 
					                                                    memory_price=memory_price)
 | 
				
			||||||
        except OpenNebulaException as err:
 | 
					        except OpenNebulaException as err:
 | 
				
			||||||
            raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
 | 
					            raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return data
 | 
					        return manager.get_template(template_id=opennebula_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create(self, validated_data):
 | 
					    def get_disk_size(self, obj):
 | 
				
			||||||
        return VirtualMachineTemplate.objects.create(**validated_data)
 | 
					        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 get_price(self, obj):
 | 
				
			||||||
    def display_value(self, instance):
 | 
					        template = obj.template
 | 
				
			||||||
        return 'Template: {}'.format(instance.get_name())
 | 
					        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."""
 | 
					    """Serializer to map the virtual machine instance into JSON format."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #TODO: Maybe we can change to template.get_cores
 | 
					    name        = serializers.CharField(read_only=True)
 | 
				
			||||||
    cores       = serializers.IntegerField(read_only=True, source='get_cores') 
 | 
					    cores       = serializers.IntegerField(read_only=True, source='template.vcpu') 
 | 
				
			||||||
    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')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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(
 | 
					    template_id = serializers.ChoiceField(
 | 
				
			||||||
                queryset=VirtualMachineTemplate.objects.all(),
 | 
					                choices=[(key.id, key.name) for key in
 | 
				
			||||||
                source='vm_template'
 | 
					                    OpenNebulaManager().get_templates()],
 | 
				
			||||||
 | 
					                source='template.template_id',
 | 
				
			||||||
 | 
					                write_only=True
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    def create(self, validated_data):
 | 
				
			||||||
        model = VirtualMachine
 | 
					        owner = validated_data['owner']
 | 
				
			||||||
        fields = ('id', 'opennebula_id', 'vm_template', 'vm_template_id', 'cores', 'name',
 | 
					        template_id = validated_data['template']['template_id']
 | 
				
			||||||
                '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)
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        try:
 | 
					        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)
 | 
					            opennebula_id = manager.create_vm(template_id)
 | 
				
			||||||
            data.update({'opennebula_id':opennebula_id})
 | 
					 | 
				
			||||||
        except OpenNebulaException as err:
 | 
					        except OpenNebulaException as err:
 | 
				
			||||||
            raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
 | 
					            raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return data
 | 
					        return manager.get_vm(opennebula_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create(self, validated_data):
 | 
					    def get_memory(self, obj):
 | 
				
			||||||
        return VirtualMachine.objects.create(**validated_data)
 | 
					        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 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, \
 | 
					from .serializers import VirtualMachineTemplateSerializer, \
 | 
				
			||||||
                         VirtualMachineSerializer
 | 
					                         VirtualMachineSerializer
 | 
				
			||||||
from .models import VirtualMachineTemplate, VirtualMachine, OpenNebulaManager
 | 
					from .models import OpenNebulaManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TemplateCreateView(generics.ListCreateAPIView):
 | 
					class TemplateCreateView(generics.ListCreateAPIView):
 | 
				
			||||||
    """This class defines the create behavior of our rest api."""
 | 
					    """This class handles the GET and POST requests."""
 | 
				
			||||||
    queryset = VirtualMachineTemplate.objects.all()
 | 
					
 | 
				
			||||||
    serializer_class = VirtualMachineTemplateSerializer
 | 
					    serializer_class = VirtualMachineTemplateSerializer
 | 
				
			||||||
 | 
					    permission_classes = (permissions.IsAuthenticated, permissions.IsAdminUser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_queryset(self):
 | 
				
			||||||
 | 
					        manager = OpenNebulaManager()
 | 
				
			||||||
 | 
					        return manager.get_templates()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def perform_create(self, serializer):
 | 
					    def perform_create(self, serializer):
 | 
				
			||||||
        """Save the post data when creating a new template."""
 | 
					        """Save the post data when creating a new template."""
 | 
				
			||||||
| 
						 | 
					@ -16,20 +32,53 @@ class TemplateCreateView(generics.ListCreateAPIView):
 | 
				
			||||||
class TemplateDetailsView(generics.RetrieveUpdateDestroyAPIView):
 | 
					class TemplateDetailsView(generics.RetrieveUpdateDestroyAPIView):
 | 
				
			||||||
    """This class handles the http GET, PUT and DELETE requests."""
 | 
					    """This class handles the http GET, PUT and DELETE requests."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    queryset = VirtualMachineTemplate.objects.all()
 | 
					 | 
				
			||||||
    serializer_class = VirtualMachineTemplateSerializer
 | 
					    serializer_class = VirtualMachineTemplateSerializer
 | 
				
			||||||
 | 
					    permission_classes = (permissions.IsAuthenticated)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_queryset(self):
 | 
				
			||||||
 | 
					        manager = OpenNebulaManager()
 | 
				
			||||||
 | 
					        return manager.get_templates()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VmCreateView(generics.ListCreateAPIView):
 | 
					class VmCreateView(generics.ListCreateAPIView):
 | 
				
			||||||
    """This class defines the create behavior of our rest api."""
 | 
					    """This class handles the GET and POST requests."""
 | 
				
			||||||
    queryset = VirtualMachine.objects.all()
 | 
					 | 
				
			||||||
    serializer_class = VirtualMachineSerializer
 | 
					    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):
 | 
					    def perform_create(self, serializer):
 | 
				
			||||||
        """Save the post data when creating a new template."""
 | 
					        """Save the post data when creating a new template."""
 | 
				
			||||||
        serializer.save()
 | 
					        serializer.save(owner=self.request.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
 | 
					class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
 | 
				
			||||||
    """This class handles the http GET, PUT and DELETE requests."""
 | 
					    """This class handles the http GET, PUT and DELETE requests."""
 | 
				
			||||||
 | 
					    permission_classes = (permissions.IsAuthenticated, )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    queryset = VirtualMachine.objects.all()
 | 
					 | 
				
			||||||
    serializer_class = VirtualMachineSerializer
 | 
					    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