From 3bb7f09d41a4f05550f4652a103aa341ad0e175d Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 23 Sep 2017 03:16:18 +0530 Subject: [PATCH 01/35] 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/35] 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/35] 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/35] 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/35] 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/35] 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/35] 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/35] 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/35] 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 313b2b2f576a741f3fa2e161ad24e1f1e02083d7 Mon Sep 17 00:00:00 2001 From: Arvind Tiwari Date: Sat, 23 Sep 2017 23:47:25 +0530 Subject: [PATCH 10/35] fixed vreate vm error --- hosting/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/views.py b/hosting/views.py index d7c4c168..e0fe041e 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -17,7 +17,7 @@ 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 ugettext +from django.utils.translation import ugettext, get_language from django.views.generic import ( View, CreateView, FormView, ListView, DetailView, DeleteView, TemplateView, UpdateView From 09dc0cde1313072ee7be54371b7cb04823ff0eb8 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Sep 2017 04:38:54 +0530 Subject: [PATCH 11/35] 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 12/35] 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 13/35] 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 14/35] 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 15/35] 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 16/35] 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 17/35] 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 18/35] 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 19/35] 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 20/35] 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 21/35] 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 f35c3dbc10f190182d57042553a9c00a36187795 Mon Sep 17 00:00:00 2001 From: Arvind Tiwari Date: Tue, 26 Sep 2017 02:38:31 +0530 Subject: [PATCH 22/35] modal check icon thinner, terminate modal text smaller --- .../datacenterlight/css/landing-page.css | 17 +++++++++ .../datacenterlight/beta_success.html | 2 +- hosting/static/hosting/css/landing-page.css | 38 +++++++++++++++++++ .../hosting/js/virtual_machine_detail.js | 21 +++++----- hosting/templates/hosting/order_detail.html | 9 ++--- .../hosting/virtual_machine_detail.html | 7 ++-- hosting/views.py | 1 - 7 files changed, 74 insertions(+), 21 deletions(-) diff --git a/datacenterlight/static/datacenterlight/css/landing-page.css b/datacenterlight/static/datacenterlight/css/landing-page.css index 6537dd0d..d50a864d 100755 --- a/datacenterlight/static/datacenterlight/css/landing-page.css +++ b/datacenterlight/static/datacenterlight/css/landing-page.css @@ -1653,3 +1653,20 @@ a.list-group-item-danger.active:focus { .panel-danger > .panel-heading .badge { background-color: #eb4d5c; } + +.checkmark { + display: inline-block; +} +.checkmark:after { + /*Add another block-level blank space*/ + content: ''; + display: block; + /*Make it a small rectangle so the border will create an L-shape*/ + width: 25px; + height: 60px; + /*Add a white border on the bottom and left, creating that 'L' */ + border: solid #777; + border-width: 0 3px 3px 0; + /*Rotate the L 45 degrees to turn it into a checkmark*/ + transform: rotate(45deg); +} diff --git a/datacenterlight/templates/datacenterlight/beta_success.html b/datacenterlight/templates/datacenterlight/beta_success.html index 2512a05c..60df607c 100644 --- a/datacenterlight/templates/datacenterlight/beta_success.html +++ b/datacenterlight/templates/datacenterlight/beta_success.html @@ -8,7 +8,7 @@

diff --git a/hosting/static/hosting/css/landing-page.css b/hosting/static/hosting/css/landing-page.css index ed8fb310..5275dd97 100644 --- a/hosting/static/hosting/css/landing-page.css +++ b/hosting/static/hosting/css/landing-page.css @@ -870,3 +870,41 @@ a.list-group-item-danger.active:focus { .panel-danger > .panel-heading .badge { background-color: #eb4d5c; } + +.checkmark { + display: inline-block; +} +.checkmark:after { + /*Add another block-level blank space*/ + content: ''; + display: block; + /*Make it a small rectangle so the border will create an L-shape*/ + width: 25px; + height: 60px; + /*Add a white border on the bottom and left, creating that 'L' */ + border: solid #777; + border-width: 0 3px 3px 0; + /*Rotate the L 45 degrees to turn it into a checkmark*/ + transform: rotate(45deg); +} + +.closemark { + display: inline-block; + width: 50px; + height: 50px; + position: relative; +} +.closemark:before, .closemark:after { + position: absolute; + left: 25px; + content: ' '; + height: 50px; + width: 2px; + background-color: #777; +} +.closemark:before { + transform: rotate(45deg); +} +.closemark:after { + transform: rotate(-45deg); +} diff --git a/hosting/static/hosting/js/virtual_machine_detail.js b/hosting/static/hosting/js/virtual_machine_detail.js index db2621c1..ca79df56 100644 --- a/hosting/static/hosting/js/virtual_machine_detail.js +++ b/hosting/static/hosting/js/virtual_machine_detail.js @@ -79,7 +79,6 @@ $(document).ready(function() { $('html,body').scrollTop(scrollmem); }); - $('.modal-text').removeClass('hide'); var create_vm_form = $('#virtual_machine_create_form'); create_vm_form.submit(function () { $('#btn-create-vm').prop('disabled', true); @@ -90,26 +89,28 @@ $(document).ready(function() { success: function (data) { if (data.status === true) { fa_icon = $('.modal-icon > .fa'); - fa_icon.attr('class', 'fa fa-check'); - $('.modal-header > .close').attr('class', 'close'); + fa_icon.attr('class', 'checkmark'); + // $('.modal-header > .close').removeClass('hidden'); $('#createvm-modal-title').text(data.msg_title); $('#createvm-modal-body').text(data.msg_body); - $('#createvm-modal').on('hidden.bs.modal', function () { - window.location = data.redirect; - }) + $('#createvm-modal-done-btn').removeClass('hide'); } }, error: function (xmlhttprequest, textstatus, message) { fa_icon = $('.modal-icon > .fa'); - fa_icon.attr('class', 'fa fa-times'); - $('.modal-header > .close').attr('class', 'close'); - $('.modal-text').addClass('hide'); + fa_icon.attr('class', 'fa fa-close'); + // $('.modal-header > .close').attr('class', 'close'); + // $('.modal-text').addClass('hide'); if (typeof(create_vm_error_message) !== 'undefined') { - $('#createvm-modal-title').text(create_vm_error_message); + $('#createvm-modal-text').text(create_vm_error_message); } $('#btn-create-vm').prop('disabled', false); + $('#createvm-modal-close-btn').removeClass('hide'); } }); return false; }); + $('#createvm-modal').on('hidden.bs.modal', function () { + $(this).find('.modal-footer .btn').addClass('hide'); + }) }); diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html index 345632d2..699a2d37 100644 --- a/hosting/templates/hosting/order_detail.html +++ b/hosting/templates/hosting/order_detail.html @@ -160,22 +160,19 @@ @@ -123,8 +123,9 @@ From 858fdd5e3f192bceba3da7bda58e3126245751ba Mon Sep 17 00:00:00 2001 From: Arvind Tiwari Date: Thu, 28 Sep 2017 02:11:11 +0530 Subject: [PATCH 32/35] Update order_detail.html --- hosting/templates/hosting/order_detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html index 08b52770..59b0bcd6 100644 --- a/hosting/templates/hosting/order_detail.html +++ b/hosting/templates/hosting/order_detail.html @@ -173,7 +173,7 @@ {% trans "Hold tight, we are processing your request" %} From 4e080c9afc98c6db23e3b2dede914897ba587ec1 Mon Sep 17 00:00:00 2001 From: PCoder Date: Thu, 28 Sep 2017 02:36:49 +0530 Subject: [PATCH 33/35] Invoice: Get VM name from id and configuration --- hosting/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hosting/views.py b/hosting/views.py index e694f55b..4d736aa8 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -694,6 +694,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, try: vm_detail = VMDetail.objects.get(vm_id=obj.vm_id) context['vm'] = vm_detail.__dict__ + context['vm']['name'] = '{}-{}'.format(context['vm']['configuration'], context['vm']['vm_id']) except VMDetail.DoesNotExist: try: manager = OpenNebulaManager( From df67fa3333c77976ae823641413ecd28c33f5018 Mon Sep 17 00:00:00 2001 From: Arvind Tiwari Date: Thu, 28 Sep 2017 02:39:55 +0530 Subject: [PATCH 34/35] period added --- hosting/templates/hosting/order_detail.html | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html index 59b0bcd6..462593f8 100644 --- a/hosting/templates/hosting/order_detail.html +++ b/hosting/templates/hosting/order_detail.html @@ -98,14 +98,12 @@

- {% comment %}

- {% trans "Period" %} - {{}} + {% trans "Period" %}: + {{ vm.created_at|date:'Y/m/d' }} - {% if vm.terminated_at %}{{ vm.terminated_at|date:'Y/m/d' }}{% else %}{% now 'Y/m/d' %}{% endif %}

- {% endcomment %}

- {% trans "Cores" %} + {% trans "Cores" %}: {% if vm.cores %} {{vm.cores|floatformat}} {% else %} @@ -113,11 +111,11 @@ {% endif %}

- {% trans "Memory" %} + {% trans "Memory" %}: {{vm.memory}} GB

- {% trans "Disk space" %} + {% trans "Disk space" %}: {{vm.disk_size}} GB

From 3ba1f191a302d4226ad44a054846ac580e4d9547 Mon Sep 17 00:00:00 2001 From: Arvind Tiwari Date: Thu, 28 Sep 2017 02:47:58 +0530 Subject: [PATCH 35/35] show period if dates exist --- hosting/templates/hosting/order_detail.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html index 462593f8..dc8de901 100644 --- a/hosting/templates/hosting/order_detail.html +++ b/hosting/templates/hosting/order_detail.html @@ -98,10 +98,12 @@

-

- {% trans "Period" %}: - {{ vm.created_at|date:'Y/m/d' }} - {% if vm.terminated_at %}{{ vm.terminated_at|date:'Y/m/d' }}{% else %}{% now 'Y/m/d' %}{% endif %} -

+ {% if vm.created_at %} +

+ {% trans "Period" %}: + {{ vm.created_at|date:'Y/m/d' }} - {% if vm.terminated_at %}{{ vm.terminated_at|date:'Y/m/d' }}{% else %}{% now 'Y/m/d' %}{% endif %} +

+ {% endif %}

{% trans "Cores" %}: {% if vm.cores %}