{% trans "We are cutting down the costs significantly!" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{% 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." %}
{% blocktrans with machine_name=virtual_machine.name %}Your Virtual Machine {{machine_name}} is successfully terminated!{% endblocktrans %}
+
+
+
{% blocktrans with machine_name=virtual_machine.name %}Your Virtual Machine {{machine_name}} is successfully terminated!{% endblocktrans %}
diff --git a/hosting/views.py b/hosting/views.py
index e2346b26..facc8c01 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
@@ -37,6 +38,7 @@ from utils.forms import (
BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm,
ResendActivationEmailForm
)
+from utils.hosting_utils import get_vm_price
from utils.mailer import BaseEmail
from utils.stripe_utils import StripeUtils
from utils.views import (
@@ -46,10 +48,11 @@ 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
-
logger = logging.getLogger(__name__)
CONNECTION_ERROR = "Your VMs cannot be displayed at the moment due to a \
@@ -682,25 +685,30 @@ 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__
+ context['vm']['name'] = '{}-{}'.format(context['vm']['configuration'], context['vm']['vm_id'])
+ 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
@@ -760,12 +768,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,
@@ -810,9 +817,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),
@@ -904,7 +912,6 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
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()
@@ -936,7 +943,8 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
extra_tags='storage')
return HttpResponseRedirect(
reverse('datacenterlight:index') + "#order_form")
-
+ price = get_vm_price(cpu=cores, memory=memory,
+ disk_size=storage)
specs = {
'cpu': cores,
'memory': memory,
@@ -1042,6 +1050,10 @@ 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
diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py
index 7c1a83ad..3c193ad7 100644
--- a/utils/hosting_utils.py
+++ b/utils/hosting_utils.py
@@ -1,4 +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 +15,48 @@ 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
+
+
+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)
diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py
index f35a6b9c..98f85d62 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
@@ -256,7 +256,19 @@ 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
+ 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)