From 3bb7f09d41a4f05550f4652a103aa341ad0e175d Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 03:16:18 +0530 Subject: [PATCH 01/25] Refactored obtaining vm price to utils.hosting_utils.get_vm_price --- utils/hosting_utils.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py index 7c1a83ad..dae8e412 100644 --- a/utils/hosting_utils.py +++ b/utils/hosting_utils.py @@ -9,3 +9,16 @@ def get_all_public_keys(customer): """ return UserHostingKey.objects.filter(user_id=customer.id).values_list( "public_key", flat=True) + + +def get_vm_price(cpu, memory, disk_size): + """ + A helper function that computes price of a VM from given cpu, ram and + ssd parameters + + :param cpu: Number of cores of the VM + :param memory: RAM of the VM + :param disk_size: Disk space of the VM + :return: The price of the VM + """ + return (cpu * 5) + (memory * 2) + (disk_size * 0.6) From 285d66466052f84ac5348f3fd1582c60556108ed Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 03:17:21 +0530 Subject: [PATCH 02/25] Refactored obtaining stripe plan name to utils.stripe_utils.get_stripe_plan_name --- utils/stripe_utils.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index f35a6b9c..cb4f6eff 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -238,7 +238,7 @@ class StripeUtils(object): @staticmethod def get_stripe_plan_id(cpu, ram, ssd, version, app='dcl', hdd=None): """ - Returns the stripe plan id string of the form + Returns the Stripe plan id string of the form `dcl-v1-cpu-2-ram-5gb-ssd-10gb` based on the input parameters :param cpu: The number of cores @@ -260,3 +260,14 @@ class StripeUtils(object): version=version, plan=dcl_plan_string) return stripe_plan_id_string + + @staticmethod + def get_stripe_plan_name(cpu, memory, disk_size): + """ + Returns the Stripe plan name + :return: + """ + return "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format( + cpu=cpu, + memory=memory, + disk_size=disk_size) From 99e5cf5587e203152b0d737c4273a98bffb4fa01 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 03:18:05 +0530 Subject: [PATCH 03/25] Using refactored get_vm_price and get_vm_plan_name functions --- datacenterlight/tests.py | 12 ++++++------ datacenterlight/views.py | 12 ++++++------ hosting/views.py | 16 ++++++++-------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/datacenterlight/tests.py b/datacenterlight/tests.py index c34c56ba..edde2db8 100644 --- a/datacenterlight/tests.py +++ b/datacenterlight/tests.py @@ -12,6 +12,7 @@ from datacenterlight.models import VMTemplate from datacenterlight.tasks import create_vm_task from membership.models import StripeCustomer from opennebula_api.serializers import VMTemplateSerializer +from utils.hosting_utils import get_vm_price from utils.models import BillingAddress from utils.stripe_utils import StripeUtils @@ -94,12 +95,11 @@ class CeleryTaskTestCase(TestCase): cpu = specs.get('cpu') memory = specs.get('memory') disk_size = specs.get('disk_size') - amount_to_be_charged = (cpu * 5) + (memory * 2) + (disk_size * 0.6) - plan_name = "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format( - cpu=cpu, - memory=memory, - disk_size=disk_size) - + amount_to_be_charged = get_vm_price(cpu=cpu, memory=memory, + disk_size=disk_size) + plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu, + memory=memory, + disk_size=disk_size) stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu, ram=memory, ssd=disk_size, diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 0521ffef..152e3e75 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -17,6 +17,7 @@ from opennebula_api.models import OpenNebulaManager from opennebula_api.serializers import VirtualMachineTemplateSerializer, \ VMTemplateSerializer from utils.forms import BillingAddressForm +from utils.hosting_utils import get_vm_price from utils.mailer import BaseEmail from utils.stripe_utils import StripeUtils from utils.tasks import send_plain_email_task @@ -532,12 +533,11 @@ class OrderConfirmationView(DetailView): cpu = specs.get('cpu') memory = specs.get('memory') disk_size = specs.get('disk_size') - amount_to_be_charged = (cpu * 5) + (memory * 2) + (disk_size * 0.6) - plan_name = "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format( - cpu=cpu, - memory=memory, - disk_size=disk_size) - + amount_to_be_charged = get_vm_price(cpu=cpu, memory=memory, + disk_size=disk_size) + plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu, + memory=memory, + disk_size=disk_size) stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu, ram=memory, ssd=disk_size, diff --git a/hosting/views.py b/hosting/views.py index e1d2feb2..f91b2e5c 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -35,6 +35,7 @@ from utils.mailer import BaseEmail from utils.stripe_utils import StripeUtils from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, \ LoginViewMixin +from utils.hosting_utils import get_vm_price from .forms import HostingUserSignupForm, HostingUserLoginForm, \ UserHostingKeyForm, generate_ssh_key_name from .mixins import ProcessVMSelectionMixin @@ -724,12 +725,11 @@ class OrdersHostingDetailView(LoginRequiredMixin, cpu = specs.get('cpu') memory = specs.get('memory') disk_size = specs.get('disk_size') - amount_to_be_charged = (cpu * 5) + (memory * 2) + (disk_size * 0.6) - plan_name = "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format( - cpu=cpu, - memory=memory, - disk_size=disk_size) - + amount_to_be_charged = get_vm_price(cpu=cpu, memory=memory, + disk_size=disk_size) + plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu, + memory=memory, + disk_size=disk_size) stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu, ram=memory, ssd=disk_size, @@ -775,8 +775,8 @@ class OrdersHostingDetailView(LoginRequiredMixin, 'redirect': reverse('hosting:virtual_machines'), 'msg_title': str(_('Thank you for the order.')), 'msg_body': str(_('Your VM will be up and running in a few moments.' - ' We will send you a confirmation email as soon as' - ' it is ready.')) + ' We will send you a confirmation email as soon as' + ' it is ready.')) } return HttpResponse(json.dumps(response), From 9ab7622a9c245c9c712e8f1ca3840487200fa3bf Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 03:25:48 +0530 Subject: [PATCH 04/25] Reformatted stripe_utils.py --- utils/stripe_utils.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index cb4f6eff..98f85d62 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -256,9 +256,10 @@ class StripeUtils(object): if hdd is not None: dcl_plan_string = '{dcl_plan_string}-hdd-{hdd}gb'.format( dcl_plan_string=dcl_plan_string, hdd=hdd) - stripe_plan_id_string = '{app}-v{version}-{plan}'.format(app=app, - version=version, - plan=dcl_plan_string) + stripe_plan_id_string = '{app}-v{version}-{plan}'.format( + app=app, + version=version, + plan=dcl_plan_string) return stripe_plan_id_string @staticmethod @@ -268,6 +269,6 @@ class StripeUtils(object): :return: """ return "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format( - cpu=cpu, - memory=memory, - disk_size=disk_size) + cpu=cpu, + memory=memory, + disk_size=disk_size) From 8de4a751079a6499e2eac508884cc1571d996add Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 12:48:21 +0530 Subject: [PATCH 05/25] Removed some occurrences of price --- datacenterlight/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 0521ffef..0b494d85 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -334,7 +334,6 @@ class IndexView(CreateView): 'cpu': cores, 'memory': memory, 'disk_size': storage, - 'price': price } this_user = { From 0bc2b22f6262c997222fbb122bd61f3fb6fa4fea Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 13:09:14 +0530 Subject: [PATCH 06/25] Reformatted datacenterlight/tasks.py --- datacenterlight/tasks.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py index 1335869b..e8b29601 100644 --- a/datacenterlight/tasks.py +++ b/datacenterlight/tasks.py @@ -52,7 +52,8 @@ def create_vm_task(self, vm_template_id, user, specs, template, stripe_customer_id, billing_address_data, billing_address_id, charge, cc_details): - logger.debug("Running create_vm_task on {}".format(current_task.request.hostname)) + logger.debug( + "Running create_vm_task on {}".format(current_task.request.hostname)) vm_id = None try: final_price = specs.get('price') @@ -142,9 +143,10 @@ def create_vm_task(self, vm_template_id, user, specs, template, email.send() if 'pass' in user: - lang = 'en-us' + lang = 'en-us' if user.get('language') is not None: - logger.debug("Language is set to {}".format(user.get('language'))) + logger.debug( + "Language is set to {}".format(user.get('language'))) lang = user.get('language') translation.activate(lang) # Send notification to the user as soon as VM has been booked From 93d36306fb5ca6a18f73a48e3eaac7c66c55ef6e Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 13:21:01 +0530 Subject: [PATCH 07/25] Removed total and price fields used in dcl flow --- datacenterlight/static/datacenterlight/js/main.js | 4 +--- .../templates/datacenterlight/calculator_form.html | 1 - datacenterlight/views.py | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/datacenterlight/static/datacenterlight/js/main.js b/datacenterlight/static/datacenterlight/js/main.js index c508d76d..82a21235 100644 --- a/datacenterlight/static/datacenterlight/js/main.js +++ b/datacenterlight/static/datacenterlight/js/main.js @@ -156,9 +156,7 @@ function _calcPricing() { var total = (cardPricing['cpu'].value * 5) + (2 * cardPricing['ram'].value) + (0.6 * cardPricing['storage'].value); total = parseFloat(total.toFixed(2)); - $("#total").text(total); - $('input[name=total]').val(total); } function form_success() { @@ -192,4 +190,4 @@ }); }) } -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/datacenterlight/templates/datacenterlight/calculator_form.html b/datacenterlight/templates/datacenterlight/calculator_form.html index cdba4809..23d0defd 100644 --- a/datacenterlight/templates/datacenterlight/calculator_form.html +++ b/datacenterlight/templates/datacenterlight/calculator_form.html @@ -77,7 +77,6 @@ {% endfor %} - diff --git a/datacenterlight/views.py b/datacenterlight/views.py index d329cb05..c7848e3d 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -275,7 +275,6 @@ class IndexView(CreateView): memory_field = forms.IntegerField(validators=[self.validate_memory]) storage = request.POST.get('storage') storage_field = forms.IntegerField(validators=[self.validate_storage]) - price = request.POST.get('total') template_id = int(request.POST.get('config')) template = VMTemplate.objects.filter( opennebula_vm_template_id=template_id).first() @@ -534,6 +533,7 @@ class OrderConfirmationView(DetailView): disk_size = specs.get('disk_size') amount_to_be_charged = get_vm_price(cpu=cpu, memory=memory, disk_size=disk_size) + specs['price'] = amount_to_be_charged plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu, memory=memory, disk_size=disk_size) From b428a0933e13bdc3c115dcb5aa8aabde4ad2761b Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 21:23:48 +0530 Subject: [PATCH 08/25] Deleted datacenterlight pricing.html --- .../templates/datacenterlight/pricing.html | 96 ------------------- 1 file changed, 96 deletions(-) delete mode 100644 datacenterlight/templates/datacenterlight/pricing.html diff --git a/datacenterlight/templates/datacenterlight/pricing.html b/datacenterlight/templates/datacenterlight/pricing.html deleted file mode 100644 index 0724a6ce..00000000 --- a/datacenterlight/templates/datacenterlight/pricing.html +++ /dev/null @@ -1,96 +0,0 @@ -{% extends "datacenterlight/base.html" %} -{% load staticfiles i18n%} -{% get_current_language as LANGUAGE_CODE %} - -{% block content %} -
- -
-

{% trans "We are cutting down the costs significantly!" %}

-
- -
- -
-
- -
-
- {% csrf_token %} - -
-

{% trans "VM hosting" %}

-
-
- 15 - CHF -
-

{% trans "VAT included" %}

-
-
-
-
-

{% trans "Hosted in Switzerland" %}

-
-
- - - Core - -
-
- - - GB RAM - -
-
- - - {% trans "GB Storage (SSD)" %} - -
- - - -
- - -
- - - - - -
- - -
-
-
- -
-

{% trans "Simple and affordable: Try our virtual machine with featherlight price." %}

- -
-

{% trans "Our VMs are hosted in Glarus, Switzerland, and our website is currently running in BETA mode. If you want more information that you did not find on our website, or if your order is more detailed, or if you encounter any technical hiccups, please contact us at support@datacenterlight.ch, our team will get in touch with you asap." %}

-
-
-
-{% endblock %} - - - From 8781905fc6df9c5002dc0584b8c2c51b465cca0f Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 21:24:42 +0530 Subject: [PATCH 09/25] Removed DataCenterLight PricingView --- datacenterlight/urls.py | 3 +-- datacenterlight/views.py | 55 +--------------------------------------- 2 files changed, 2 insertions(+), 56 deletions(-) diff --git a/datacenterlight/urls.py b/datacenterlight/urls.py index 772e691d..a8d8f49d 100644 --- a/datacenterlight/urls.py +++ b/datacenterlight/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import url from .views import IndexView, BetaProgramView, LandingProgramView, \ - BetaAccessView, PricingView, SuccessView, \ + BetaAccessView, SuccessView, \ PaymentOrderView, OrderConfirmationView, \ WhyDataCenterLightView, ContactUsView @@ -15,7 +15,6 @@ urlpatterns = [ name='whydatacenterlight'), url(r'^beta-program/?$', BetaProgramView.as_view(), name='beta'), url(r'^landing/?$', LandingProgramView.as_view(), name='landing'), - url(r'^pricing/?$', PricingView.as_view(), name='pricing'), url(r'^payment/?$', PaymentOrderView.as_view(), name='payment'), url(r'^order-confirmation/?$', OrderConfirmationView.as_view(), name='order_confirmation'), diff --git a/datacenterlight/views.py b/datacenterlight/views.py index c7848e3d..a2baf717 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -4,7 +4,6 @@ from django.contrib import messages from django.core.exceptions import ValidationError from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect -from django.shortcuts import redirect from django.shortcuts import render from django.utils.translation import ugettext_lazy as _ from django.views.decorators.cache import cache_control @@ -13,9 +12,7 @@ from django.views.generic import FormView, CreateView, TemplateView, DetailView from datacenterlight.tasks import create_vm_task from hosting.models import HostingOrder from membership.models import CustomUser, StripeCustomer -from opennebula_api.models import OpenNebulaManager -from opennebula_api.serializers import VirtualMachineTemplateSerializer, \ - VMTemplateSerializer +from opennebula_api.serializers import VMTemplateSerializer from utils.forms import BillingAddressForm from utils.hosting_utils import get_vm_price from utils.mailer import BaseEmail @@ -89,56 +86,6 @@ class SuccessView(TemplateView): return render(request, self.template_name) -class PricingView(TemplateView): - template_name = "datacenterlight/pricing.html" - - def get(self, request, *args, **kwargs): - try: - manager = OpenNebulaManager() - templates = manager.get_templates() - - context = { - 'templates': VirtualMachineTemplateSerializer(templates, - many=True).data, - } - except: - messages.error(request, - 'We have a temporary problem to connect to our backend. \ - Please try again in a few minutes' - ) - context = { - 'error': 'connection' - } - - return render(request, self.template_name, context) - - def post(self, request): - - cores = request.POST.get('cpu') - memory = request.POST.get('ram') - storage = request.POST.get('storage') - price = request.POST.get('total') - - template_id = int(request.POST.get('config')) - manager = OpenNebulaManager() - template = manager.get_template(template_id) - - request.session['template'] = VirtualMachineTemplateSerializer( - template).data - - if not request.user.is_authenticated(): - request.session['next'] = reverse('hosting:payment') - - request.session['specs'] = { - 'cpu': cores, - 'memory': memory, - 'disk_size': storage, - 'price': price, - } - - return redirect(reverse('hosting:payment')) - - class BetaAccessView(FormView): template_name = "datacenterlight/beta_access.html" form_class = BetaAccessForm From 09dc0cde1313072ee7be54371b7cb04823ff0eb8 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Sep 2017 04:38:54 +0530 Subject: [PATCH 10/25] Removed unwanted js code that was causing error --- hosting/templates/hosting/choice_ssh_keys.html | 15 --------------- hosting/templates/hosting/user_keys.html | 16 ---------------- 2 files changed, 31 deletions(-) diff --git a/hosting/templates/hosting/choice_ssh_keys.html b/hosting/templates/hosting/choice_ssh_keys.html index 3a377388..87224156 100644 --- a/hosting/templates/hosting/choice_ssh_keys.html +++ b/hosting/templates/hosting/choice_ssh_keys.html @@ -47,20 +47,5 @@ window.location.href = '{{next_url}}'; {% endif %} - - - - - {%endblock%} diff --git a/hosting/templates/hosting/user_keys.html b/hosting/templates/hosting/user_keys.html index 1cfb880c..6810efdf 100644 --- a/hosting/templates/hosting/user_keys.html +++ b/hosting/templates/hosting/user_keys.html @@ -101,21 +101,5 @@ window.location.href = '{{next_url}}'; {% endif %} - - - - - {%endblock%} From 0974376e9f5df6298324afaba5441dcce4210133 Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Sun, 24 Sep 2017 09:34:30 +0200 Subject: [PATCH 11/25] Reformatted code --- hosting/views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index c21a6cd8..99ab6f05 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -47,7 +47,6 @@ from .mixins import ProcessVMSelectionMixin from .models import HostingOrder, HostingBill, HostingPlan, UserHostingKey from datacenterlight.models import VMTemplate - logger = logging.getLogger(__name__) CONNECTION_ERROR = "Your VMs cannot be displayed at the moment due to a \ @@ -806,9 +805,10 @@ class OrdersHostingDetailView(LoginRequiredMixin, 'status': True, 'redirect': reverse('hosting:virtual_machines'), 'msg_title': str(_('Thank you for the order.')), - 'msg_body': str(_('Your VM will be up and running in a few moments.' - ' We will send you a confirmation email as soon as' - ' it is ready.')) + 'msg_body': str( + _('Your VM will be up and running in a few moments.' + ' We will send you a confirmation email as soon as' + ' it is ready.')) } return HttpResponse(json.dumps(response), @@ -937,7 +937,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View): return HttpResponseRedirect( reverse('datacenterlight:index') + "#order_form") price = get_vm_price(cpu=cores, memory=memory, - disk_size=storage) + disk_size=storage) specs = { 'cpu': cores, 'memory': memory, From a45679d89a3c97da8e046f4b7464645a550de6b1 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 00:00:45 +0530 Subject: [PATCH 12/25] Added VMDetail model --- hosting/models.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hosting/models.py b/hosting/models.py index 478ed745..73c082bb 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -159,3 +159,16 @@ class HostingBill(AssignPermissionsMixin, models.Model): instance = cls.objects.create(customer=customer, billing_address=billing_address) return instance + + +class VMDetail(models.Model): + user = models.ForeignKey(CustomUser) + vm_id = models.IntegerField(default=0) + disk_size = models.FloatField(default=0.0) + cores = models.FloatField(default=0.0) + memory = models.FloatField(default=0.0) + configuration = models.CharField(default='', max_length=25) + ipv4 = models.TextField(default='') + ipv6 = models.TextField(default='') + created_at = models.DateTimeField(auto_now_add=True) + terminated_at = models.DateTimeField(null=True) From f4899ffc184a849f4a56b4796667ad19ae0b5c9e Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 00:01:48 +0530 Subject: [PATCH 13/25] Added missing get_language import --- hosting/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/views.py b/hosting/views.py index d7c4c168..7ce66e57 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -16,7 +16,7 @@ from django.http import Http404, HttpResponseRedirect, HttpResponse from django.shortcuts import redirect, render from django.utils.http import urlsafe_base64_decode from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import get_language, ugettext_lazy as _ from django.utils.translation import ugettext from django.views.generic import ( View, CreateView, FormView, ListView, DetailView, DeleteView, From 7278a201358dbc4c00c5cbefb860d35c0d63d571 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 00:02:36 +0530 Subject: [PATCH 14/25] Added get_or_create_vm_detail function --- datacenterlight/tasks.py | 5 +++-- utils/hosting_utils.py | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py index 1335869b..fd83a320 100644 --- a/datacenterlight/tasks.py +++ b/datacenterlight/tasks.py @@ -9,11 +9,11 @@ from django.utils import translation from django.utils.translation import ugettext_lazy as _ from dynamicweb.celery import app -from hosting.models import HostingOrder, HostingBill +from hosting.models import HostingOrder, HostingBill, VMDetail from membership.models import StripeCustomer, CustomUser from opennebula_api.models import OpenNebulaManager from opennebula_api.serializers import VirtualMachineSerializer -from utils.hosting_utils import get_all_public_keys +from utils.hosting_utils import get_all_public_keys, get_or_create_vm_detail from utils.forms import UserBillingAddressForm from utils.mailer import BaseEmail from utils.models import BillingAddress @@ -174,6 +174,7 @@ def create_vm_task(self, vm_template_id, user, specs, template, logger.debug("New VM ID is {vm_id}".format(vm_id=vm_id)) if new_host is not None: custom_user = CustomUser.objects.get(email=user.get('email')) + get_or_create_vm_detail(custom_user, manager, vm_id) if custom_user is not None: public_keys = get_all_public_keys(custom_user) keys = [{'value': key, 'state': True} for key in diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py index 7c1a83ad..7faf2a29 100644 --- a/utils/hosting_utils.py +++ b/utils/hosting_utils.py @@ -1,5 +1,10 @@ -from hosting.models import UserHostingKey +import logging +from oca.pool import WrongIdError +from hosting.models import UserHostingKey, VMDetail +from opennebula_api.serializers import VirtualMachineSerializer + +logger = logging.getLogger(__name__) def get_all_public_keys(customer): """ @@ -9,3 +14,35 @@ def get_all_public_keys(customer): """ return UserHostingKey.objects.filter(user_id=customer.id).values_list( "public_key", flat=True) + + +def get_or_create_vm_detail(user, manager, vm_id): + """ + Returns VMDetail object related to given vm_id. Creates the object + if it does not exist + + :param vm_id: The ID of the VM which should be greater than 0. + :param user: The CustomUser object that owns this VM + :param manager: The OpenNebulaManager object + :return: The VMDetail object. None if vm_id is less than or equal to 0. + Also, for the cases where the VMDetail does not exist and we can not + fetch data about the VM from OpenNebula, the function returns None + """ + if vm_id <= 0: + return None + try: + vm_detail_obj = VMDetail.objects.get(vm_id=vm_id) + except VMDetail.DoesNotExist: + try: + vm_obj = manager.get_vm(vm_id) + except (WrongIdError, ConnectionRefusedError) as e: + logger.error(str(e)) + return None + vm = VirtualMachineSerializer(vm_obj).data + vm_detail_obj = VMDetail.objects.create( + user=user, vm_id=vm_id, disk_size=vm['disk_size'], + cores=vm['cores'], memory=vm['memory'], + configuration=vm['configuration'], ipv4=vm['ipv4'], + ipv6=vm['ipv6'] + ) + return vm_detail_obj From f2f2fc22df5aae4a0f787ecc20ed4f38bdcb4a1e Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 00:30:28 +0530 Subject: [PATCH 15/25] Update VMDetail's terminated_at on delete of a vm --- hosting/views.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hosting/views.py b/hosting/views.py index 7ce66e57..19c02979 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1,6 +1,7 @@ import json import logging import uuid +from datetime import datetime from time import sleep from django import forms @@ -43,7 +44,9 @@ from utils.views import ( from .forms import HostingUserSignupForm, HostingUserLoginForm, \ UserHostingKeyForm, generate_ssh_key_name from .mixins import ProcessVMSelectionMixin -from .models import HostingOrder, HostingBill, HostingPlan, UserHostingKey +from .models import ( + HostingOrder, HostingBill, HostingPlan, UserHostingKey, VMDetail +) from datacenterlight.models import VMTemplate @@ -1043,6 +1046,9 @@ class VirtualMachineView(LoginRequiredMixin, View): except WrongIdError: response['status'] = True response['text'] = ugettext('Terminated') + vm_detail_obj = VMDetail.objects.filter(vm_id=opennebula_vm_id).first() + vm_detail_obj.terminated_at = datetime.utcnow() + vm_detail_obj.save() break except BaseException: break From 114511e9240762c283d5452783d494e0fc3bb21f Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 00:34:18 +0530 Subject: [PATCH 16/25] Fixed some flake8 warnings --- datacenterlight/tasks.py | 4 ++-- utils/hosting_utils.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py index fd83a320..a5496d83 100644 --- a/datacenterlight/tasks.py +++ b/datacenterlight/tasks.py @@ -9,7 +9,7 @@ from django.utils import translation from django.utils.translation import ugettext_lazy as _ from dynamicweb.celery import app -from hosting.models import HostingOrder, HostingBill, VMDetail +from hosting.models import HostingOrder, HostingBill from membership.models import StripeCustomer, CustomUser from opennebula_api.models import OpenNebulaManager from opennebula_api.serializers import VirtualMachineSerializer @@ -142,7 +142,7 @@ def create_vm_task(self, vm_template_id, user, specs, template, email.send() if 'pass' in user: - lang = 'en-us' + lang = 'en-us' if user.get('language') is not None: logger.debug("Language is set to {}".format(user.get('language'))) lang = user.get('language') diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py index 7faf2a29..09f81536 100644 --- a/utils/hosting_utils.py +++ b/utils/hosting_utils.py @@ -6,6 +6,7 @@ from opennebula_api.serializers import VirtualMachineSerializer logger = logging.getLogger(__name__) + def get_all_public_keys(customer): """ Returns all the public keys of the user From 83ccb9cffae5475e3b8626a0e90dbe07b2c5a29f Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 00:36:33 +0530 Subject: [PATCH 17/25] Added vmdetail migration file --- hosting/migrations/0043_vmdetail.py | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 hosting/migrations/0043_vmdetail.py diff --git a/hosting/migrations/0043_vmdetail.py b/hosting/migrations/0043_vmdetail.py new file mode 100644 index 00000000..66966233 --- /dev/null +++ b/hosting/migrations/0043_vmdetail.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2017-09-24 18:12 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('hosting', '0042_hostingorder_subscription_id'), + ] + + operations = [ + migrations.CreateModel( + name='VMDetail', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('vm_id', models.IntegerField(default=0)), + ('disk_size', models.FloatField(default=0.0)), + ('cores', models.FloatField(default=0.0)), + ('memory', models.FloatField(default=0.0)), + ('configuration', models.CharField(default='', max_length=25)), + ('ipv4', models.TextField(default='')), + ('ipv6', models.TextField(default='')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('terminated_at', models.DateTimeField(null=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] From f2213305f61fff09509d4f82dd0b5db875ec9edd Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 00:46:39 +0530 Subject: [PATCH 18/25] Reformatted hosting views.py --- hosting/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index 19c02979..77bf05b7 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -49,7 +49,6 @@ from .models import ( ) from datacenterlight.models import VMTemplate - logger = logging.getLogger(__name__) CONNECTION_ERROR = "Your VMs cannot be displayed at the moment due to a \ @@ -1046,7 +1045,8 @@ class VirtualMachineView(LoginRequiredMixin, View): except WrongIdError: response['status'] = True response['text'] = ugettext('Terminated') - vm_detail_obj = VMDetail.objects.filter(vm_id=opennebula_vm_id).first() + vm_detail_obj = VMDetail.objects.filter( + vm_id=opennebula_vm_id).first() vm_detail_obj.terminated_at = datetime.utcnow() vm_detail_obj.save() break From 7fcece40c1d986c66380509d55f250aca06fd125 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 01:49:00 +0530 Subject: [PATCH 19/25] Using VMDetail model to show order details --- hosting/views.py | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index 77bf05b7..577715ca 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -680,25 +680,29 @@ class OrdersHostingDetailView(LoginRequiredMixin, if obj is not None: # invoice for previous order try: - manager = OpenNebulaManager( - email=owner.email, password=owner.password - ) - vm = manager.get_vm(obj.vm_id) - context['vm'] = VirtualMachineSerializer(vm).data - except WrongIdError: - messages.error( - self.request, - _('The VM you are looking for is unavailable at the ' - 'moment. Please contact Data Center Light support.') - ) - self.kwargs['error'] = 'WrongIdError' - context['error'] = 'WrongIdError' - except ConnectionRefusedError: - messages.error( - self.request, - _('In order to create a VM, you need to create/upload ' - 'your SSH KEY first.') - ) + vm_detail = VMDetail.objects.get(vm_id=obj.vm_id) + context['vm'] = vm_detail.__dict__ + except VMDetail.DoesNotExist: + try: + manager = OpenNebulaManager( + email=owner.email, password=owner.password + ) + vm = manager.get_vm(obj.vm_id) + context['vm'] = VirtualMachineSerializer(vm).data + except WrongIdError: + messages.error( + self.request, + _('The VM you are looking for is unavailable at the ' + 'moment. Please contact Data Center Light support.') + ) + self.kwargs['error'] = 'WrongIdError' + context['error'] = 'WrongIdError' + except ConnectionRefusedError: + messages.error( + self.request, + _('In order to create a VM, you need to create/upload ' + 'your SSH KEY first.') + ) elif not card_details.get('response_object'): # new order, failed to get card details context['failed_payment'] = True From 46d82268f41c002a6b6d74fad89ae62db8f7efbe Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Sep 2017 02:04:40 +0530 Subject: [PATCH 20/25] Show terminated in invoice for VM that has been terminated --- hosting/templates/hosting/order_detail.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html index 345632d2..ece84a9e 100644 --- a/hosting/templates/hosting/order_detail.html +++ b/hosting/templates/hosting/order_detail.html @@ -42,7 +42,9 @@

{% trans "Status" %}: - {% if order.status == 'Approved' %} + {% if vm.terminated_at %} + {% trans "Terminated" %} + {% elif order.status == 'Approved' %} {% trans "Approved" %} {% else %} {% trans "Declined" %} @@ -202,4 +204,4 @@ -{% endblock js_extra %} \ No newline at end of file +{% endblock js_extra %} From aceaecc748f25957f4b579e10ef5861fafbdce97 Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Wed, 27 Sep 2017 13:08:23 +0200 Subject: [PATCH 21/25] Add .gitconfig and .sql to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 46bfbf54..2222eddf 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,5 @@ secret-key .env *.mo *.log +.gitconfig +.sql From 172fffe7bedee6a275ecd1316109281f3df30ee5 Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Wed, 27 Sep 2017 13:13:16 +0200 Subject: [PATCH 22/25] .gitignore: change .sql to *.sql --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2222eddf..3d466d50 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,4 @@ secret-key *.mo *.log .gitconfig -.sql +*.sql From f1d273b9d0b8d9836737c7f5125312792dc25eb3 Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Wed, 27 Sep 2017 13:46:00 +0200 Subject: [PATCH 23/25] .gitignore: remove .gitconfig --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3d466d50..cfef66a1 100644 --- a/.gitignore +++ b/.gitignore @@ -36,5 +36,4 @@ secret-key .env *.mo *.log -.gitconfig *.sql From edd79bcd3244075d77a6e58fe1f5ea3c8753b350 Mon Sep 17 00:00:00 2001 From: PCoder Date: Thu, 28 Sep 2017 01:19:26 +0530 Subject: [PATCH 24/25] Update Changelog --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index de602e8d..15bdd6b9 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,5 @@ +Next: + * #3764: [hosting] Show cancelled VMs' invoices 1.2.3: 2017-09-25 * #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email * #3731: [dcl, hosting] Added cdist ssh key handler From 5a43a38e196cb971565cf81b4086184f3a95a649 Mon Sep 17 00:00:00 2001 From: PCoder Date: Thu, 28 Sep 2017 01:57:17 +0530 Subject: [PATCH 25/25] Update Changelog --- Changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changelog b/Changelog index 15bdd6b9..58835832 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,10 @@ Next: * #3764: [hosting] Show cancelled VMs' invoices + * #3736: [dcl] Refactor the place where we compute the VM price + * #3730: [dcl] Refactor price parameter passed in the DCL flow + * #3807: [dcl] Remove PricingView as it is no more used + * #3813: [hosting] JS error in create ssh key page + 1.2.3: 2017-09-25 * #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email * #3731: [dcl, hosting] Added cdist ssh key handler