From 2ff8b9e4a59815ed40e937c1bbbada95c99adaf7 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Fri, 5 May 2017 14:59:11 +0200 Subject: [PATCH 01/15] Add hosting bill view, model and urls --- hosting/admin.py | 4 +- hosting/migrations/0028_managevms.py | 24 ++++++ hosting/migrations/0029_managevm.py | 24 ++++++ hosting/migrations/0030_hostingbill.py | 31 ++++++++ hosting/models.py | 16 ++++ hosting/templates/hosting/bill_detail.html | 93 ++++++++++++++++++++++ hosting/templates/hosting/bills.html | 60 ++++++++++++++ hosting/urls.py | 5 +- hosting/views.py | 76 +++++++++++++++++- 9 files changed, 330 insertions(+), 3 deletions(-) create mode 100644 hosting/migrations/0028_managevms.py create mode 100644 hosting/migrations/0029_managevm.py create mode 100644 hosting/migrations/0030_hostingbill.py create mode 100644 hosting/templates/hosting/bill_detail.html create mode 100644 hosting/templates/hosting/bills.html diff --git a/hosting/admin.py b/hosting/admin.py index b4f1ba24..ee4e7415 100644 --- a/hosting/admin.py +++ b/hosting/admin.py @@ -5,7 +5,8 @@ from django.core.urlresolvers import reverse from utils.mailer import BaseEmail from .forms import HostingOrderAdminForm -from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, ManageVM +from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, \ + ManageVM, HostingBill from .opennebula_functions import HostingManageVMAdmin @@ -98,3 +99,4 @@ admin.site.register(HostingOrder, HostingOrderAdmin) admin.site.register(VirtualMachineType) admin.site.register(VirtualMachinePlan, VirtualMachinePlanAdmin) admin.site.register(ManageVM, HostingManageVMAdmin) +admin.site.register(HostingBill) diff --git a/hosting/migrations/0028_managevms.py b/hosting/migrations/0028_managevms.py new file mode 100644 index 00000000..b71480f2 --- /dev/null +++ b/hosting/migrations/0028_managevms.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2017-04-24 04:24 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hosting', '0027_auto_20160711_0210'), + ] + + operations = [ + migrations.CreateModel( + name='ManageVMs', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'managed': False, + }, + ), + ] diff --git a/hosting/migrations/0029_managevm.py b/hosting/migrations/0029_managevm.py new file mode 100644 index 00000000..946e4264 --- /dev/null +++ b/hosting/migrations/0029_managevm.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2017-04-24 04:25 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hosting', '0028_managevms'), + ] + + operations = [ + migrations.CreateModel( + name='ManageVM', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'managed': False, + }, + ), + ] diff --git a/hosting/migrations/0030_hostingbill.py b/hosting/migrations/0030_hostingbill.py new file mode 100644 index 00000000..edb01aed --- /dev/null +++ b/hosting/migrations/0030_hostingbill.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2017-05-05 11:50 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import utils.mixins + + +class Migration(migrations.Migration): + + dependencies = [ + ('utils', '0005_auto_20170322_1443'), + ('membership', '0006_auto_20160526_0445'), + ('hosting', '0029_managevm'), + ] + + operations = [ + migrations.CreateModel( + name='HostingBill', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('billing_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='utils.BillingAddress')), + ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='membership.StripeCustomer')), + ], + options={ + 'permissions': (('view_hostingbill', 'View Hosting Bill'),), + }, + bases=(utils.mixins.AssignPermissionsMixin, models.Model), + ), + ] diff --git a/hosting/models.py b/hosting/models.py index b24dc855..a27fb487 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -1,5 +1,6 @@ import os +import oca from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.functional import cached_property @@ -233,3 +234,18 @@ class ManageVM(models.Model): class Meta: managed = False + +class HostingBill(AssignPermissionsMixin, models.Model): + customer = models.ForeignKey(StripeCustomer) + billing_address = models.ForeignKey(BillingAddress) + + permissions = ('view_hostingbill',) + + class Meta: + permissions = ( + ('view_hostingbill', 'View Hosting Bill'), + ) + + def __str__(self): + return "%s" % (self.customer.user.email) + diff --git a/hosting/templates/hosting/bill_detail.html b/hosting/templates/hosting/bill_detail.html new file mode 100644 index 00000000..1904bf82 --- /dev/null +++ b/hosting/templates/hosting/bill_detail.html @@ -0,0 +1,93 @@ +{% extends "hosting/base_short.html" %} +{% load staticfiles bootstrap3 %} +{% load i18n %} +{% block content %} + +<h1> {{ bill }} </h1> +<div class="container"> + {# Adress bar #} + <div class="row"> + <div class="invoice-title"> + <h2>{% trans "Invoice"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{bill.id}}</h3> + </div> + </div> + <hr> + <div class="row"> + <div class="col-sm-6"> + <address> + {{bill.customer.user.name}}<br> + {{bill.billing_address.street_address}},{{bill.billing_address.postal_code}}<br> + {{bill.billing_address.city}}, {{bill.billing_address.country}}. + </address> + </div> + <div class="col-sm-6 text-right"> + <address> + {% trans "ungleich GmbH" %}<br> + {% trans "buchhaltung@ungleich.ch" %}<br> + {% trans "Hauptstrasse 14"%}<br> + {% trans "CH-8775 Luchsingen"%}<br> + {% trans "Mwst-Nummer: CHE-109.549.333 MWST"%}<br> + + </address> + </div> + </div> + <hr> + <table class="table table-bordered"> + {# Bill header #} + <thead> + <tr> + <th>Name</th> + <th>Cores</th> + <th>Memory</th> + <th>Disk Size</th> + <th>Price</th> + </tr> + </thead> + <tbody> + {# Bill items#} + {% for vm in vms %} + <tr> + <td>{{ vm.name }}</td> + <td>{{ vm.cores }}</td> + <td>{{ vm.memory }}</td> + <td>{{ vm.disk_size }}</td> + <td>{{ vm.price }}</td> + + </tr> + {% endfor %} + {# Bill total#} + <tr> + <td> {% trans "Total:" %} </td> + <td> </td> + <td> </td> + <td> {% trans "Brutto" %} </td> + <td> {% trans "Netto" %} </td> + </tr> + </tbody> + </table> + <hr> + {# Bill Footer #} + <div class="row"> + {% trans "Alles Preise in CHF mit 8% Mehrwertsteuer." %} + {% trans "Betrag zahlbar innerhalb von 30 Tagen ab Rechnungseingang." %} + {% trans "Kontoverbindung:" %} + <div class="row"> + <div class="col-sm-6"> + {% trans "IBAN:" %} + </div> + <div class="col-sm-6"> + {% trans "BIC:" %} + </div> + </div> + <div class="row"> + <div class="col-sm-6"> + {% trans "CH02 ............" %} + </div> + <div class="col-sm-6"> + {% trans "POFICHBEXXX" %} + </div> + </div> + </div> +</div> +{% endblock %} + diff --git a/hosting/templates/hosting/bills.html b/hosting/templates/hosting/bills.html new file mode 100644 index 00000000..cc1883fb --- /dev/null +++ b/hosting/templates/hosting/bills.html @@ -0,0 +1,60 @@ +{% extends "hosting/base_short.html" %} +{% load staticfiles bootstrap3 %} +{% load i18n %} + +{% block content %} + + <div> + <div class="container orders-container"> + <div class="row"> + <div class="col-md-8 col-md-offset-2"> + <table class="table borderless table-hover"> + <h3>{% trans "Customers"%}</h3> + <br/> + <thead> + <tr> + <th>{% trans "Name"%}</th> + <th>{% trans "Email"%}</th> + <th></th> + </tr> + </thead> + <tbody> + {% for user in users %} + <tr> + <td>{{ user.name}}</td> + <td>{{ user.email}} CHF</td> + <td> + <button type="button" class="btn btn-default"><a + href="{% url 'hosting:bills' user.id %}">{% trans "View Bill"%}</a> + </button> + </td> + </tr> + {% endfor %} + + </tbody> + </table> + + {% if is_paginated %} + <div class="pagination"> + <span class="page-links"> + {% if page_obj.has_previous %} + <a href="{{ request.path }}?page={{ page_obj.previous_page_number }}">{% trans "previous"%}</a> + {% endif %} + <span class="page-current"> + Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}. + </span> + {% if page_obj.has_next %} + <a href="{{ request.path }}?page={{ page_obj.next_page_number }}">{% trans "next"%}</a> + {% endif %} + </span> + </div> + {% endif %} + + </div> + + </div> + </div> + + </div> + +{% endblock %} diff --git a/hosting/urls.py b/hosting/urls.py index 5ceeba97..1df6be9e 100644 --- a/hosting/urls.py +++ b/hosting/urls.py @@ -4,7 +4,8 @@ from .views import DjangoHostingView, RailsHostingView, PaymentVMView,\ NodeJSHostingView, LoginView, SignupView, IndexView, \ OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\ VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \ - MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView + MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, \ + HostingPricingView, HostingBillListView, HostingBillDetailView urlpatterns = [ url(r'index/?$', IndexView.as_view(), name='index'), @@ -15,6 +16,8 @@ urlpatterns = [ url(r'payment/?$', PaymentVMView.as_view(), name='payment'), url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'), url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'), + url(r'bills/?$', HostingBillListView.as_view(), name='bills'), + url(r'bills/(?P<pk>\d+)/?$', HostingBillDetailView.as_view(), name='bills'), url(r'cancel_order/(?P<pk>\d+)/?$', OrdersHostingDeleteView.as_view(), name='delete_order'), url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'), url(r'my-virtual-machines/(?P<pk>\d+)/?$', VirtualMachineView.as_view(), diff --git a/hosting/views.py b/hosting/views.py index 6b21c91b..c9634200 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1,3 +1,4 @@ +import oca from django.shortcuts import render from django.core.urlresolvers import reverse_lazy, reverse @@ -19,7 +20,7 @@ from utils.stripe_utils import StripeUtils from utils.forms import BillingAddressForm, PasswordResetRequestForm from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin from utils.mailer import BaseEmail -from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder +from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, HostingBill from .forms import HostingUserSignupForm, HostingUserLoginForm from .mixins import ProcessVMSelectionMixin @@ -328,6 +329,10 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai permission_required = ['view_hostingorder'] model = HostingOrder + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + print(context) + return context class OrdersHostingListView(LoginRequiredMixin, ListView): template_name = "hosting/orders.html" @@ -396,3 +401,72 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, UpdateView email.send() return HttpResponseRedirect(self.get_success_url()) + +class HostingBillListView(LoginRequiredMixin, ListView): + template_name = "hosting/bills.html" + login_url = reverse_lazy('hosting:login') + context_object_name = "users" + model = StripeCustomer + paginate_by = 10 + ordering = '-id' + #TODO show only clients i.e. get_query_set + +class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailView): + template_name = "hosting/bill_detail.html" + login_url = reverse_lazy('hosting:login') + permission_required = ['view_hostingview'] + context_object_name = "bill" + model = HostingBill + + def get_object(self, queryset=None): + #Get HostingBill for primary key (Select from customer users) + pk = self.kwargs['pk'] + return HostingBill.objects.filter(customer__id=pk).first() + + def get_context_data(self, **kwargs): + # Get User + user_email = self.object.customer.user.email + # Get context + context = super(DetailView, self).get_context_data(**kwargs) + # Add VMs to context + context['vms'] = [] + + # Connect to open nebula server + client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, + settings.OPENNEBULA_PASSWORD), + "{protocol}://{domain}:{port}{endpoint}".format( + protocol=settings.OPENNEBULA_PROTOCOL, + domain=settings.OPENNEBULA_DOMAIN, + port=settings.OPENNEBULA_PORT, + endpoint=settings.OPENNEBULA_ENDPOINT + )) + # Get open nebula user id for given email + user_pool = oca.UserPool(client) + user_pool.info() + user_id = user_pool.get_by_name('alain').id + + # Get vm_pool for given user_id + vm_pool = oca.VirtualMachinePool(client) + vm_pool.info(filter=user_id) + # Add vm in vm_pool to context + for vm in vm_pool: + #TODO: Replace with vm plan + name = vm.name + cores = int(vm.template.vcpu) + memory = int(vm.template.memory) / 1024 + # Check if vm has more than one disk + if 'DISK' in vm.template.multiple: + disk_size = 0 + for disk in vm.template.disks: + disk_size += int(disk.size) / 1024 + else: + disk_size = int(vm.template.disk.size) / 1024 + vm = {} + vm['name'] = name + vm['price'] = 0.6 * disk_size + 2 * memory + 5 * cores + vm['disk_size'] = disk_size + vm['cores'] = cores + vm['memory'] = memory + context['vms'].append(vm) + + return context From 673e8a0c79df1b5d601c75913950d3c77e0a3e1e Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Sat, 6 May 2017 14:44:08 +0200 Subject: [PATCH 02/15] Add total_price to HostingBill model --- .../0031_hostingbill_total_price.py | 20 ++++ hosting/models.py | 1 + hosting/templates/hosting/bill_detail.html | 91 +++++++++---------- hosting/views.py | 10 +- 4 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 hosting/migrations/0031_hostingbill_total_price.py diff --git a/hosting/migrations/0031_hostingbill_total_price.py b/hosting/migrations/0031_hostingbill_total_price.py new file mode 100644 index 00000000..0a15c1f9 --- /dev/null +++ b/hosting/migrations/0031_hostingbill_total_price.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2017-05-06 12:30 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hosting', '0030_hostingbill'), + ] + + operations = [ + migrations.AddField( + model_name='hostingbill', + name='total_price', + field=models.FloatField(default=0.0), + ), + ] diff --git a/hosting/models.py b/hosting/models.py index a27fb487..8c6a2c0d 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -238,6 +238,7 @@ class ManageVM(models.Model): class HostingBill(AssignPermissionsMixin, models.Model): customer = models.ForeignKey(StripeCustomer) billing_address = models.ForeignKey(BillingAddress) + total_price = models.FloatField(default=0.0) permissions = ('view_hostingbill',) diff --git a/hosting/templates/hosting/bill_detail.html b/hosting/templates/hosting/bill_detail.html index 1904bf82..b58c21f7 100644 --- a/hosting/templates/hosting/bill_detail.html +++ b/hosting/templates/hosting/bill_detail.html @@ -7,29 +7,29 @@ <div class="container"> {# Adress bar #} <div class="row"> - <div class="invoice-title"> - <h2>{% trans "Invoice"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{bill.id}}</h3> - </div> + <div class="invoice-title"> + <h2>{% trans "Invoice"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{bill.id}}</h3> + </div> </div> <hr> <div class="row"> - <div class="col-sm-6"> - <address> - {{bill.customer.user.name}}<br> - {{bill.billing_address.street_address}},{{bill.billing_address.postal_code}}<br> - {{bill.billing_address.city}}, {{bill.billing_address.country}}. - </address> - </div> - <div class="col-sm-6 text-right"> - <address> - {% trans "ungleich GmbH" %}<br> - {% trans "buchhaltung@ungleich.ch" %}<br> - {% trans "Hauptstrasse 14"%}<br> - {% trans "CH-8775 Luchsingen"%}<br> - {% trans "Mwst-Nummer: CHE-109.549.333 MWST"%}<br> + <div class="col-sm-6"> + <address> + {{bill.customer.user.name}}<br> + {{bill.billing_address.street_address}},{{bill.billing_address.postal_code}}<br> + {{bill.billing_address.city}}, {{bill.billing_address.country}}. + </address> + </div> + <div class="col-sm-6 text-right"> + <address> + {% trans "ungleich GmbH" %}<br> + {% trans "buchhaltung@ungleich.ch" %}<br> + {% trans "Hauptstrasse 14"%}<br> + {% trans "CH-8775 Luchsingen"%}<br> + {% trans "Mwst-Nummer: CHE-109.549.333 MWST"%}<br> - </address> - </div> + </address> + </div> </div> <hr> <table class="table table-bordered"> @@ -48,45 +48,42 @@ {% for vm in vms %} <tr> <td>{{ vm.name }}</td> - <td>{{ vm.cores }}</td> - <td>{{ vm.memory }}</td> - <td>{{ vm.disk_size }}</td> - <td>{{ vm.price }}</td> + <td><span class="pull-right">{{ vm.cores }}</span></td> + <td><span class="pull-right">{{ vm.memory|floatformat }} GiB </span></td> + <td><span class="pull-right">{{ vm.disk_size|floatformat }} GiB </span></td> + <td><span class="pull-right">{{ vm.price|floatformat }} CHF</span></td> </tr> {% endfor %} {# Bill total#} <tr> - <td> {% trans "Total:" %} </td> - <td> </td> - <td> </td> - <td> {% trans "Brutto" %} </td> - <td> {% trans "Netto" %} </td> + <td colspan=4> {% trans "Total:" %} </td> + <td> <span class="pull-right">{{ bill.total_price}} CHF </span></td> </tr> </tbody> </table> <hr> {# Bill Footer #} <div class="row"> - {% trans "Alles Preise in CHF mit 8% Mehrwertsteuer." %} - {% trans "Betrag zahlbar innerhalb von 30 Tagen ab Rechnungseingang." %} - {% trans "Kontoverbindung:" %} - <div class="row"> - <div class="col-sm-6"> - {% trans "IBAN:" %} - </div> - <div class="col-sm-6"> - {% trans "BIC:" %} - </div> - </div> - <div class="row"> - <div class="col-sm-6"> - {% trans "CH02 ............" %} - </div> - <div class="col-sm-6"> - {% trans "POFICHBEXXX" %} - </div> - </div> + {% trans "Alles Preise in CHF mit 8% Mehrwertsteuer." %} + {% trans "Betrag zahlbar innerhalb von 30 Tagen ab Rechnungseingang." %} + {% trans "Kontoverbindung:" %} + <div class="row"> + <div class="col-sm-6"> + {% trans "IBAN:" %} + </div> + <div class="col-sm-6"> + {% trans "BIC:" %} + </div> + </div> + <div class="row"> + <div class="col-sm-6"> + {% trans "CH02 ............" %} + </div> + <div class="col-sm-6"> + {% trans "POFICHBEXXX" %} + </div> + </div> </div> </div> {% endblock %} diff --git a/hosting/views.py b/hosting/views.py index c9634200..b552063a 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -448,9 +448,10 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV # Get vm_pool for given user_id vm_pool = oca.VirtualMachinePool(client) vm_pool.info(filter=user_id) + # Reset total price + context['bill'].total_price = 0 # Add vm in vm_pool to context for vm in vm_pool: - #TODO: Replace with vm plan name = vm.name cores = int(vm.template.vcpu) memory = int(vm.template.memory) / 1024 @@ -461,12 +462,17 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV disk_size += int(disk.size) / 1024 else: disk_size = int(vm.template.disk.size) / 1024 + + #TODO: Replace with vm plan + price = 0.6 * disk_size + 2 * memory + 5 * cores vm = {} vm['name'] = name - vm['price'] = 0.6 * disk_size + 2 * memory + 5 * cores + vm['price'] = price vm['disk_size'] = disk_size vm['cores'] = cores vm['memory'] = memory context['vms'].append(vm) + context['bill'].total_price += price + context['bill'].save() return context From 6f252def5d9aa7bda7ea9bb99036a69cb3b1114d Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Sat, 6 May 2017 15:16:10 +0200 Subject: [PATCH 03/15] Return error if HostingBill object does not exist --- hosting/templates/hosting/bill_error.html | 14 ++++++++++++++ hosting/views.py | 8 ++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 hosting/templates/hosting/bill_error.html diff --git a/hosting/templates/hosting/bill_error.html b/hosting/templates/hosting/bill_error.html new file mode 100644 index 00000000..5374ecb5 --- /dev/null +++ b/hosting/templates/hosting/bill_error.html @@ -0,0 +1,14 @@ +{% extends "hosting/base_short.html" %} +{% load staticfiles bootstrap3 %} +{% load i18n %} +{% block content %} + +<div class="container"> + <div class="container orders-container"> + <h1>Error</h1> + <p> Could not get HostingBill object for client. </p> + <p> Please create a HostingBill object via the admin page </p> + </div> +</div> +{% endblock %} + diff --git a/hosting/views.py b/hosting/views.py index b552063a..b5a18597 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -424,10 +424,14 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV return HostingBill.objects.filter(customer__id=pk).first() def get_context_data(self, **kwargs): - # Get User - user_email = self.object.customer.user.email # Get context context = super(DetailView, self).get_context_data(**kwargs) + # Get User + try: + user_email = self.object.customer.user.email + except AttributeError: + self.template_name = 'hosting/bill_error.html' + return context # Add VMs to context context['vms'] = [] From bd362cb6191fd2a2449d42b58823b547984669b1 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Sat, 6 May 2017 15:28:18 +0200 Subject: [PATCH 04/15] Change to user_email add TODOs --- hosting/views.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hosting/views.py b/hosting/views.py index b5a18597..923a6f29 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1,4 +1,5 @@ import oca +import socket from django.shortcuts import render from django.core.urlresolvers import reverse_lazy, reverse @@ -7,6 +8,7 @@ from django.views.generic import View, CreateView, FormView, ListView, DetailVie DeleteView, TemplateView, UpdateView from django.http import HttpResponseRedirect from django.contrib.auth import authenticate, login +from django.contrib import messages from django.conf import settings from guardian.mixins import PermissionRequiredMixin @@ -24,6 +26,9 @@ from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, Hostin from .forms import HostingUserSignupForm, HostingUserLoginForm from .mixins import ProcessVMSelectionMixin +from oca.exceptions import OpenNebulaException +from oca.pool import WrongNameError + class DjangoHostingView(ProcessVMSelectionMixin, View): template_name = "hosting/django.html" @@ -436,6 +441,7 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV context['vms'] = [] # Connect to open nebula server + # TODO: handle potential connection error client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, settings.OPENNEBULA_PASSWORD), "{protocol}://{domain}:{port}{endpoint}".format( @@ -447,11 +453,13 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV # Get open nebula user id for given email user_pool = oca.UserPool(client) user_pool.info() - user_id = user_pool.get_by_name('alain').id + # TODO: handle potential name error + user_id = user_pool.get_by_name(user_email).id # Get vm_pool for given user_id vm_pool = oca.VirtualMachinePool(client) vm_pool.info(filter=user_id) + # Reset total price context['bill'].total_price = 0 # Add vm in vm_pool to context From 4ab8963149f851687170ae55e26d75e7be221fd8 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Sun, 7 May 2017 06:43:28 +0200 Subject: [PATCH 05/15] Follow fat models small views Based on the recommondation in 'Two scoops of Django' I moved the code for accessing the customers vm from the view to the model. --- hosting/models.py | 55 ++++++++++++++++++++++++++++++++++++++++ hosting/views.py | 64 ++--------------------------------------------- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 4ca46844..e48f2f4b 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -267,3 +267,58 @@ class HostingBill(AssignPermissionsMixin, models.Model): def __str__(self): return "%s" % (self.customer.user.email) + def get_vms(self): + # Get User + user_email = self.customer.user.email + + # Connect to open nebula server + # TODO: handle potential connection error + client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, + settings.OPENNEBULA_PASSWORD), + "{protocol}://{domain}:{port}{endpoint}".format( + protocol=settings.OPENNEBULA_PROTOCOL, + domain=settings.OPENNEBULA_DOMAIN, + port=settings.OPENNEBULA_PORT, + endpoint=settings.OPENNEBULA_ENDPOINT + )) + # Get open nebula user id for given email + user_pool = oca.UserPool(client) + user_pool.info() + # TODO: handle potential name error + user_id = user_pool.get_by_name(user_email).id + + # Get vm_pool for given user_id + vm_pool = oca.VirtualMachinePool(client) + vm_pool.info(filter=user_id) + + # Reset total price + self.total_price = 0 + vms = [] + # Add vm in vm_pool to context + for vm in vm_pool: + name = vm.name + cores = int(vm.template.vcpu) + memory = int(vm.template.memory) / 1024 + # Check if vm has more than one disk + if 'DISK' in vm.template.multiple: + disk_size = 0 + for disk in vm.template.disks: + disk_size += int(disk.size) / 1024 + else: + disk_size = int(vm.template.disk.size) / 1024 + + #TODO: Replace with vm plan + price = 0.6 * disk_size + 2 * memory + 5 * cores + vm = {} + vm['name'] = name + vm['price'] = price + vm['disk_size'] = disk_size + vm['cores'] = cores + vm['memory'] = memory + vms.append(vm) + self.total_price += price + + self.save() + return vms + + diff --git a/hosting/views.py b/hosting/views.py index 07bda4d2..91b92667 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -386,11 +386,6 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai permission_required = ['view_hostingorder'] model = HostingOrder - def get_context_data(self, **kwargs): - context = super(DetailView, self).get_context_data(**kwargs) - print(context) - return context - class OrdersHostingListView(LoginRequiredMixin, ListView): template_name = "hosting/orders.html" login_url = reverse_lazy('hosting:login') @@ -520,60 +515,5 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV def get_context_data(self, **kwargs): # Get context context = super(DetailView, self).get_context_data(**kwargs) - # Get User - try: - user_email = self.object.customer.user.email - except AttributeError: - self.template_name = 'hosting/bill_error.html' - return context - # Add VMs to context - context['vms'] = [] - - # Connect to open nebula server - # TODO: handle potential connection error - client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, - settings.OPENNEBULA_PASSWORD), - "{protocol}://{domain}:{port}{endpoint}".format( - protocol=settings.OPENNEBULA_PROTOCOL, - domain=settings.OPENNEBULA_DOMAIN, - port=settings.OPENNEBULA_PORT, - endpoint=settings.OPENNEBULA_ENDPOINT - )) - # Get open nebula user id for given email - user_pool = oca.UserPool(client) - user_pool.info() - # TODO: handle potential name error - user_id = user_pool.get_by_name(user_email).id - - # Get vm_pool for given user_id - vm_pool = oca.VirtualMachinePool(client) - vm_pool.info(filter=user_id) - - # Reset total price - context['bill'].total_price = 0 - # Add vm in vm_pool to context - for vm in vm_pool: - name = vm.name - cores = int(vm.template.vcpu) - memory = int(vm.template.memory) / 1024 - # Check if vm has more than one disk - if 'DISK' in vm.template.multiple: - disk_size = 0 - for disk in vm.template.disks: - disk_size += int(disk.size) / 1024 - else: - disk_size = int(vm.template.disk.size) / 1024 - - #TODO: Replace with vm plan - price = 0.6 * disk_size + 2 * memory + 5 * cores - vm = {} - vm['name'] = name - vm['price'] = price - vm['disk_size'] = disk_size - vm['cores'] = cores - vm['memory'] = memory - context['vms'].append(vm) - context['bill'].total_price += price - - context['bill'].save() - return context + # Get vms + context['vms'] = self.get_object().get_vms() From c2a76e6c39576169c6933bd293f8c20746d9dd92 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Sun, 7 May 2017 16:09:41 +0200 Subject: [PATCH 06/15] Merge migrations and fix spacing --- hosting/migrations/0037_merge.py | 16 ++++++++++++++++ hosting/models.py | 5 +++-- 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 hosting/migrations/0037_merge.py diff --git a/hosting/migrations/0037_merge.py b/hosting/migrations/0037_merge.py new file mode 100644 index 00000000..091a16c5 --- /dev/null +++ b/hosting/migrations/0037_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2017-05-07 04:49 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('hosting', '0031_hostingbill_total_price'), + ('hosting', '0036_auto_20170506_2312'), + ] + + operations = [ + ] diff --git a/hosting/models.py b/hosting/models.py index e48f2f4b..63bf8654 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -4,6 +4,7 @@ import oca from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.functional import cached_property +from django.conf import settings from Crypto.PublicKey import RSA from stored_messages.settings import stored_messages_settings @@ -293,7 +294,7 @@ class HostingBill(AssignPermissionsMixin, models.Model): # Reset total price self.total_price = 0 - vms = [] + vms = [] # Add vm in vm_pool to context for vm in vm_pool: name = vm.name @@ -319,6 +320,6 @@ class HostingBill(AssignPermissionsMixin, models.Model): self.total_price += price self.save() - return vms + return vms From f871bb2aba11d1aab12543c74d71080cc0eb7d60 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Mon, 8 May 2017 01:43:47 +0200 Subject: [PATCH 07/15] Show correct user name and email --- hosting/templates/hosting/bills.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hosting/templates/hosting/bills.html b/hosting/templates/hosting/bills.html index cc1883fb..1e789e12 100644 --- a/hosting/templates/hosting/bills.html +++ b/hosting/templates/hosting/bills.html @@ -21,8 +21,8 @@ <tbody> {% for user in users %} <tr> - <td>{{ user.name}}</td> - <td>{{ user.email}} CHF</td> + <td>{{ user.user.name}}</td> + <td>{{ user.user.email}}</td> <td> <button type="button" class="btn btn-default"><a href="{% url 'hosting:bills' user.id %}">{% trans "View Bill"%}</a> From b4ec750728a4c9dfe90c3eeca3488f6bdf5bc1b5 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Mon, 8 May 2017 01:56:02 +0200 Subject: [PATCH 08/15] Return error page if HostingBill is None --- hosting/views.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index 91b92667..4c66f40e 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -510,10 +510,18 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV def get_object(self, queryset=None): #Get HostingBill for primary key (Select from customer users) pk = self.kwargs['pk'] - return HostingBill.objects.filter(customer__id=pk).first() + object = HostingBill.objects.filter(customer__id=pk).first() + if object is None: + self.template_name = 'hosting/bill_error.html' + return object def get_context_data(self, **kwargs): # Get context context = super(DetailView, self).get_context_data(**kwargs) # Get vms - context['vms'] = self.get_object().get_vms() + try: + context['vms'] = self.get_object().get_vms() + except: + pass + + return context From a22c8cad51fc92b095663bf041024b8111fee211 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Mon, 8 May 2017 02:46:11 +0200 Subject: [PATCH 09/15] Fix cosmetic detail --- hosting/templates/hosting/bill_detail.html | 155 +++++++++++---------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/hosting/templates/hosting/bill_detail.html b/hosting/templates/hosting/bill_detail.html index b58c21f7..449fa1bb 100644 --- a/hosting/templates/hosting/bill_detail.html +++ b/hosting/templates/hosting/bill_detail.html @@ -3,88 +3,89 @@ {% load i18n %} {% block content %} -<h1> {{ bill }} </h1> <div class="container"> - {# Adress bar #} - <div class="row"> - <div class="invoice-title"> - <h2>{% trans "Invoice"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{bill.id}}</h3> + <div class="orders-container"> + {# Adress bar #} + <div class="row"> + <div class="invoice-title"> + <h2>{% trans "Invoice"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{bill.id}}</h3> + </div> </div> - </div> - <hr> - <div class="row"> - <div class="col-sm-6"> - <address> - {{bill.customer.user.name}}<br> - {{bill.billing_address.street_address}},{{bill.billing_address.postal_code}}<br> - {{bill.billing_address.city}}, {{bill.billing_address.country}}. - </address> - </div> - <div class="col-sm-6 text-right"> - <address> - {% trans "ungleich GmbH" %}<br> - {% trans "buchhaltung@ungleich.ch" %}<br> - {% trans "Hauptstrasse 14"%}<br> - {% trans "CH-8775 Luchsingen"%}<br> - {% trans "Mwst-Nummer: CHE-109.549.333 MWST"%}<br> + <hr> + <div class="row"> + <div class="col-sm-6"> + <address> + {{bill.customer.user.name}}<br> + {{bill.billing_address.street_address}},{{bill.billing_address.postal_code}}<br> + {{bill.billing_address.city}}, {{bill.billing_address.country}}. + </address> + </div> + <div class="col-sm-6 text-right"> + <address> + {% trans "ungleich GmbH" %}<br> + {% trans "buchhaltung@ungleich.ch" %}<br> + {% trans "Hauptstrasse 14"%}<br> + {% trans "CH-8775 Luchsingen"%}<br> + {% trans "Mwst-Nummer: CHE-109.549.333 MWST"%}<br> - </address> - </div> - </div> - <hr> - <table class="table table-bordered"> - {# Bill header #} - <thead> - <tr> - <th>Name</th> - <th>Cores</th> - <th>Memory</th> - <th>Disk Size</th> - <th>Price</th> - </tr> - </thead> - <tbody> - {# Bill items#} - {% for vm in vms %} + </address> + </div> + </div> + <hr> + <table class="table table-bordered"> + {# Bill header #} + <thead> <tr> - <td>{{ vm.name }}</td> - <td><span class="pull-right">{{ vm.cores }}</span></td> - <td><span class="pull-right">{{ vm.memory|floatformat }} GiB </span></td> - <td><span class="pull-right">{{ vm.disk_size|floatformat }} GiB </span></td> - <td><span class="pull-right">{{ vm.price|floatformat }} CHF</span></td> - + <th>Name</th> + <th>Cores</th> + <th>Memory</th> + <th>Disk Size</th> + <th>Price</th> </tr> - {% endfor %} - {# Bill total#} - <tr> - <td colspan=4> {% trans "Total:" %} </td> - <td> <span class="pull-right">{{ bill.total_price}} CHF </span></td> - </tr> - </tbody> - </table> - <hr> - {# Bill Footer #} - <div class="row"> - {% trans "Alles Preise in CHF mit 8% Mehrwertsteuer." %} - {% trans "Betrag zahlbar innerhalb von 30 Tagen ab Rechnungseingang." %} - {% trans "Kontoverbindung:" %} - <div class="row"> - <div class="col-sm-6"> - {% trans "IBAN:" %} - </div> - <div class="col-sm-6"> - {% trans "BIC:" %} - </div> - </div> - <div class="row"> - <div class="col-sm-6"> - {% trans "CH02 ............" %} - </div> - <div class="col-sm-6"> - {% trans "POFICHBEXXX" %} - </div> - </div> - </div> + </thead> + <tbody> + {# Bill items#} + {% for vm in vms %} + <tr> + <td>{{ vm.name }}</td> + <td><span class="pull-right">{{ vm.cores }}</span></td> + <td><span class="pull-right">{{ vm.memory|floatformat }} GiB </span></td> + <td><span class="pull-right">{{ vm.disk_size|floatformat }} GiB </span></td> + <td><span class="pull-right">{{ vm.price|floatformat }} CHF</span></td> + + </tr> + {% endfor %} + {# Bill total#} + <tr> + <td colspan=4> {% trans "Total:" %} </td> + <td> <span class="pull-right">{{ bill.total_price}} CHF </span></td> + </tr> + </tbody> + </table> + <hr> + {# Bill Footer #} + <div class="row"> + {% trans "Alles Preise in CHF mit 8% Mehrwertsteuer." %} + {% trans "Betrag zahlbar innerhalb von 30 Tagen ab Rechnungseingang." %} + {% trans "Kontoverbindung:" %} + <div class="row"> + <div class="col-sm-6"> + {% trans "IBAN:" %} + </div> + <div class="col-sm-6"> + {% trans "BIC:" %} + </div> + </div> + <div class="row"> + <div class="col-sm-6"> + {% trans "CH02 ............" %} + </div> + <div class="col-sm-6"> + {% trans "POFICHBEXXX" %} + </div> + </div> + </div> + <div> </div> {% endblock %} From ae69a56ab2705e604c23f4155297a999a9ed7b88 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Mon, 8 May 2017 02:47:38 +0200 Subject: [PATCH 10/15] Add error handling --- hosting/models.py | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 63bf8654..83bebdef 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -1,4 +1,5 @@ import os +import socket import oca from django.db import models @@ -13,6 +14,8 @@ from membership.models import StripeCustomer, CustomUser from utils.models import BillingAddress from utils.mixins import AssignPermissionsMixin from .managers import VMPlansManager +from oca.exceptions import OpenNebulaException +from oca.pool import WrongNameError class VirtualMachineType(models.Model): @@ -273,21 +276,31 @@ class HostingBill(AssignPermissionsMixin, models.Model): user_email = self.customer.user.email # Connect to open nebula server - # TODO: handle potential connection error - client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, - settings.OPENNEBULA_PASSWORD), - "{protocol}://{domain}:{port}{endpoint}".format( - protocol=settings.OPENNEBULA_PROTOCOL, - domain=settings.OPENNEBULA_DOMAIN, - port=settings.OPENNEBULA_PORT, - endpoint=settings.OPENNEBULA_ENDPOINT - )) + try: + client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, + settings.OPENNEBULA_PASSWORD), + "{protocol}://{domain}:{port}{endpoint}".format( + protocol=settings.OPENNEBULA_PROTOCOL, + domain=settings.OPENNEBULA_DOMAIN, + port=settings.OPENNEBULA_PORT, + endpoint=settings.OPENNEBULA_ENDPOINT + )) + except OpenNebulaException as err: + logger.error("Error : {0}".format(err)) + return None + except socket.timeout: + logger.error("Socket timeout error.") + return None + + # Get open nebula user id for given email user_pool = oca.UserPool(client) user_pool.info() - # TODO: handle potential name error - user_id = user_pool.get_by_name(user_email).id - + try: + user_id = user_pool.get_by_name(user_email).id + except WrongNameError as wrong_name_err: + logger.error("User {0} does not exist.", user_email) + return None # Get vm_pool for given user_id vm_pool = oca.VirtualMachinePool(client) vm_pool.info(filter=user_id) From c745a8c40261d61de4e3912bb84704c7774c77aa Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Mon, 8 May 2017 16:00:42 +0200 Subject: [PATCH 11/15] Remove comment I assume that only clients are StripeCustomer objects --- hosting/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hosting/views.py b/hosting/views.py index 376cda00..70f1b113 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -499,7 +499,6 @@ class HostingBillListView(LoginRequiredMixin, ListView): model = StripeCustomer paginate_by = 10 ordering = '-id' - #TODO show only clients i.e. get_query_set class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailView): template_name = "hosting/bill_detail.html" From 38b2aa8986e0ba7419086a637bd3266fa9b2a78f Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Tue, 9 May 2017 04:40:41 +0200 Subject: [PATCH 12/15] Create HostingBill obj when payment's successful --- hosting/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hosting/views.py b/hosting/views.py index 2bb21af0..ca1e854c 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -321,6 +321,8 @@ class PaymentVMView(LoginRequiredMixin, FormView): # Create a Hosting Order order = HostingOrder.create(vm_plan=plan, customer=customer, billing_address=billing_address) + # Create a Hosting Bill + bill = HostingBill.create(customer=customer, billing_address=billing_address) # Make stripe charge to a customer stripe_utils = StripeUtils() From 7010c76c728a0cd8c2e4bcc456bc44392b0ddbc2 Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Tue, 9 May 2017 04:41:35 +0200 Subject: [PATCH 13/15] Add floatformat --- hosting/templates/hosting/bill_detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/templates/hosting/bill_detail.html b/hosting/templates/hosting/bill_detail.html index 449fa1bb..2d7f04b4 100644 --- a/hosting/templates/hosting/bill_detail.html +++ b/hosting/templates/hosting/bill_detail.html @@ -58,7 +58,7 @@ {# Bill total#} <tr> <td colspan=4> {% trans "Total:" %} </td> - <td> <span class="pull-right">{{ bill.total_price}} CHF </span></td> + <td> <span class="pull-right">{{ bill.total_price|floatformat}} CHF </span></td> </tr> </tbody> </table> From 6dedf3693e5d12d07661d4c14cd1dccb5c18bd9e Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Tue, 9 May 2017 04:41:45 +0200 Subject: [PATCH 14/15] Change to use OpenNebulaManager --- hosting/models.py | 66 ++++++++++------------------------------------- 1 file changed, 13 insertions(+), 53 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 4a15789e..635b15a0 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -311,67 +311,27 @@ class HostingBill(AssignPermissionsMixin, models.Model): def __str__(self): return "%s" % (self.customer.user.email) + @classmethod + def create(cls, customer=None, billing_address=None): + instance = cls.objects.create(customer=customer, billing_address=billing_address) + return instance + def get_vms(self): - # Get User - user_email = self.customer.user.email + email = self.customer.user.email + # Get opennebula client + opennebula_client = OpenNebulaManager() - # Connect to open nebula server - try: - client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, - settings.OPENNEBULA_PASSWORD), - "{protocol}://{domain}:{port}{endpoint}".format( - protocol=settings.OPENNEBULA_PROTOCOL, - domain=settings.OPENNEBULA_DOMAIN, - port=settings.OPENNEBULA_PORT, - endpoint=settings.OPENNEBULA_ENDPOINT - )) - except OpenNebulaException as err: - logger.error("Error : {0}".format(err)) - return None - except socket.timeout: - logger.error("Socket timeout error.") - return None - - - # Get open nebula user id for given email - user_pool = oca.UserPool(client) - user_pool.info() - try: - user_id = user_pool.get_by_name(user_email).id - except WrongNameError as wrong_name_err: - logger.error("User {0} does not exist.", user_email) - return None - # Get vm_pool for given user_id - vm_pool = oca.VirtualMachinePool(client) - vm_pool.info(filter=user_id) + # 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: - name = vm.name - cores = int(vm.template.vcpu) - memory = int(vm.template.memory) / 1024 - # Check if vm has more than one disk - if 'DISK' in vm.template.multiple: - disk_size = 0 - for disk in vm.template.disks: - disk_size += int(disk.size) / 1024 - else: - disk_size = int(vm.template.disk.size) / 1024 - - #TODO: Replace with vm plan - price = 0.6 * disk_size + 2 * memory + 5 * cores - vm = {} - vm['name'] = name - vm['price'] = price - vm['disk_size'] = disk_size - vm['cores'] = cores - vm['memory'] = memory - vms.append(vm) - self.total_price += price - + vm_data = OpenNebulaManager.parse_vm(vm) + self.total_price += vm_data['price'] + vms.append(vm_data) self.save() return vms From 63052df6c9a45379480903765d685ab88344baca Mon Sep 17 00:00:00 2001 From: Modulos <modulos@protonmail.com> Date: Tue, 9 May 2017 05:05:58 +0200 Subject: [PATCH 15/15] Change to new OpenNebula functions --- hosting/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/models.py b/hosting/models.py index 37b18379..b59b7f5a 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -339,7 +339,7 @@ class HostingBill(AssignPermissionsMixin, models.Model): def get_vms(self): email = self.customer.user.email # Get opennebula client - opennebula_client = OpenNebulaManager() + opennebula_client = OpenNebulaManager(create_user=False) # Get vm pool vm_pool = opennebula_client.get_vms(email)