diff --git a/dynamicweb/urls.py b/dynamicweb/urls.py
index 5e6b99ee..adbe0242 100644
--- a/dynamicweb/urls.py
+++ b/dynamicweb/urls.py
@@ -12,6 +12,8 @@ import debug_toolbar
urlpatterns = [ url(r'^index.html$', LandingView.as_view()),
url(r'^hosting/', include('hosting.urls', namespace="hosting")),
+ url(r'^open_api/', include('opennebula_api.urls',
+ namespace='opennebula_api')),
url(r'^railshosting/', RailsHostingView.as_view(), name="rails.hosting"),
url(r'^nodehosting/', NodeJSHostingView.as_view(), name="node.hosting"),
url(r'^djangohosting/', DjangoHostingView.as_view(), name="django.hosting"),
diff --git a/hosting/admin.py b/hosting/admin.py
index ee4e7415..4f2f15e1 100644
--- a/hosting/admin.py
+++ b/hosting/admin.py
@@ -4,99 +4,8 @@ from django.core.urlresolvers import reverse
from utils.mailer import BaseEmail
-from .forms import HostingOrderAdminForm
-from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, \
- ManageVM, HostingBill
-from .opennebula_functions import HostingManageVMAdmin
+from .models import HostingOrder, HostingBill
-class HostingOrderAdmin(admin.ModelAdmin):
- # fields = ('slug', 'imdb_link', 'start', 'finish', 'added_by')
- list_display = ('id', 'created_at', 'plan', 'user')
- search_fields = ['vm_plan__id', 'customer__user__email']
-
- def save_model(self, request, obj, form, change):
- if not change:
- customer = form.cleaned_data.get('customer')
-
- # Get and set billing address from the lastest charged order
- last_order = HostingOrder.objects.filter(customer=customer).latest('id')
- billing_address = last_order.billing_address
- obj.billing_address = billing_address
-
- charge = form.cleaned_data.get('charge')
- # Associate an order with a stripe payment
- obj.set_stripe_charge(charge)
-
- # If the Stripe payment was successed, set order status approved
- obj.set_approved()
-
- # Assigning permissions
- obj.assign_permissions(customer.user)
-
- context = {
- 'order': obj,
- 'vm': obj.vm_plan,
- 'base_url': "{0}://{1}".format(request.scheme, request.get_host())
- }
- email_data = {
- 'subject': 'Your VM plan has been charged',
- 'to': obj.customer.user.email,
- 'context': context,
- 'template_name': 'vm_charged',
- 'template_path': 'hosting/emails/'
- }
- email = BaseEmail(**email_data)
- email.send()
-
- obj.save()
- return obj
-
- def get_form(self, request, obj=None, **kwargs):
- if obj is None:
- kwargs['form'] = HostingOrderAdminForm
- return super(HostingOrderAdmin, self).get_form(request, obj, **kwargs)
-
- def user(self, obj):
- email = obj.customer.user.email
- user_url = reverse("admin:membership_customuser_change", args=[obj.customer.user.id])
- return format_html("{email} ", url=user_url, email=email)
-
- def plan(self, obj):
- vm_name = obj.vm_plan.name
- vm_url = reverse("admin:hosting_virtualmachineplan_change", args=[obj.vm_plan.id])
- return format_html("{vm_name} ", url=vm_url, vm_name=vm_name)
-
- plan.short_description = "Virtual Machine Plan"
-
-
-class VirtualMachinePlanAdmin(admin.ModelAdmin):
- list_display = ('name', 'id', 'email')
-
- def email(self, obj):
- return obj.hosting_orders.latest('id').customer.user.email
-
- def save_model(self, request, obj, form, change):
- email = self.email(obj)
- if 'status' in form.changed_data:
- context = {
- 'vm': obj,
- 'base_url': "{0}://{1}".format(request.scheme, request.get_host())
- }
- email_data = {
- 'subject': 'Your VM has been activated',
- 'to': email,
- 'context': context,
- 'template_name': 'vm_status_changed',
- 'template_path': 'hosting/emails/'
- }
- email = BaseEmail(**email_data)
- email.send()
- obj.save()
-
-
-admin.site.register(HostingOrder, HostingOrderAdmin)
-admin.site.register(VirtualMachineType)
-admin.site.register(VirtualMachinePlan, VirtualMachinePlanAdmin)
-admin.site.register(ManageVM, HostingManageVMAdmin)
+admin.site.register(HostingOrder)
admin.site.register(HostingBill)
diff --git a/hosting/forms.py b/hosting/forms.py
index b143140d..c94c4822 100644
--- a/hosting/forms.py
+++ b/hosting/forms.py
@@ -7,39 +7,7 @@ from django.contrib.auth import authenticate
from utils.stripe_utils import StripeUtils
-from .models import HostingOrder, VirtualMachinePlan, UserHostingKey
-
-
-class HostingOrderAdminForm(forms.ModelForm):
-
- class Meta:
- model = HostingOrder
- fields = ['vm_plan', 'customer']
-
- def clean(self):
- customer = self.cleaned_data.get('customer')
- vm_plan = self.cleaned_data.get('vm_plan')
-
- if vm_plan.status == VirtualMachinePlan.CANCELED_STATUS:
- raise forms.ValidationError("""You can't make a charge over
- a canceled virtual machine plan""")
-
- if not customer:
- raise forms.ValidationError("""You need select a costumer""")
-
- # Make a charge to the customer
- stripe_utils = StripeUtils()
- charge_response = stripe_utils.make_charge(customer=customer.stripe_id,
- amount=vm_plan.price)
- charge = charge_response.get('response_object')
- if not charge:
- raise forms.ValidationError(charge_response.get('error'))
-
- self.cleaned_data.update({
- 'charge': charge
- })
- return self.cleaned_data
-
+from .models import HostingOrder, UserHostingKey
class HostingUserLoginForm(forms.Form):
diff --git a/hosting/migrations/0038_auto_20170512_1006.py b/hosting/migrations/0038_auto_20170512_1006.py
new file mode 100644
index 00000000..716faa38
--- /dev/null
+++ b/hosting/migrations/0038_auto_20170512_1006.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2017-05-12 10:06
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('hosting', '0037_merge'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='virtualmachineplan',
+ name='vm_type',
+ ),
+ migrations.RemoveField(
+ model_name='hostingorder',
+ name='vm_plan',
+ ),
+ migrations.AddField(
+ model_name='hostingorder',
+ name='vm_id',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.DeleteModel(
+ name='VirtualMachinePlan',
+ ),
+ migrations.DeleteModel(
+ name='VirtualMachineType',
+ ),
+ ]
diff --git a/hosting/migrations/0039_hostingorder_price.py b/hosting/migrations/0039_hostingorder_price.py
new file mode 100644
index 00000000..0d4945fa
--- /dev/null
+++ b/hosting/migrations/0039_hostingorder_price.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2017-05-12 16:37
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('hosting', '0038_auto_20170512_1006'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='hostingorder',
+ name='price',
+ field=models.FloatField(default=0),
+ preserve_default=False,
+ ),
+ ]
diff --git a/hosting/mixins.py b/hosting/mixins.py
index 404c4cb9..359b1434 100644
--- a/hosting/mixins.py
+++ b/hosting/mixins.py
@@ -1,35 +1,20 @@
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
-from .models import VirtualMachinePlan, VirtualMachineType
class ProcessVMSelectionMixin(object):
def post(self, request, *args, **kwargs):
- configuration = request.POST.get('configuration')
- configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
- vm_template = request.POST.get('vm_template')
- vm_type = VirtualMachineType.objects.get(id=vm_template)
- vm_specs = vm_type.get_specs()
+ #configuration = request.POST.get('configuration')
+ #configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
+ vm_template_id = request.POST.get('vm_template_id')
vm_specs.update({
'configuration_display': configuration_display,
'configuration': configuration,
- 'final_price': vm_type.final_price,
- 'vm_template': vm_template
+ 'vm_template_id': vm_template_id
})
- # vm_specs = {
- # # 'cores': request.POST.get('cores'),
- # # 'memory': request.POST.get('memory'),
- # # 'disk_size': request.POST.get('disk_space'),
- # # 'hosting_company': request.POST.get('hosting_company'),
- # # 'location_code': request.POST.get('location_code'),
- # # 'configuration': hosting,
- # # 'configuration_detail': configuration_detail,
- # 'final_price': request.POST.get('final_price')
- # }
request.session['vm_specs'] = vm_specs
if not request.user.is_authenticated():
- request.session['vm_specs'] = vm_specs
request.session['next'] = reverse('hosting:payment')
return redirect(reverse('hosting:login'))
return redirect(reverse('hosting:payment'))
diff --git a/hosting/models.py b/hosting/models.py
index 892aa45d..188f1733 100644
--- a/hosting/models.py
+++ b/hosting/models.py
@@ -1,5 +1,7 @@
import os
import socket
+import logging
+
import oca
from django.db import models
@@ -19,252 +21,15 @@ from .managers import VMPlansManager
from oca.exceptions import OpenNebulaException
from oca.pool import WrongNameError
-import logging
logger = logging.getLogger(__name__)
-class VirtualMachineType(models.Model):
-
- description = models.TextField()
- base_price = models.FloatField()
- memory_price = models.FloatField()
- core_price = models.FloatField()
- disk_size_price = models.FloatField()
- cores = models.IntegerField()
- memory = models.IntegerField()
- disk_size = models.IntegerField()
-
- def __str__(self):
- return "VM Type %s" % (self.id)
-
- @cached_property
- def final_price(self):
- price = self.cores * self.core_price
- price += self.memory * self.memory_price
- price += self.disk_size * self.disk_size_price
- return price
-
- @classmethod
- def get_serialized_vm_types(cls):
- return [vm.get_serialized_data()
- for vm in cls.objects.all()]
-
- def calculate_price(self):
- price = self.cores * self.core_price
- price += self.memory * self.memory_price
- price += self.disk_size * self.disk_size_price
- # price += self.base_price
- return price
-
- # @classmethod
- # def get_price(cls, vm_template):
- # return cls.BASE_PRICE * vm_template
-
- def get_specs(self):
- return {
- 'memory': self.memory,
- 'cores': self.cores,
- 'disk_size': self.disk_size
- }
-
- # def calculate_price(self, vm_template):
- # price = self.base_price * vm_template
- # return price
-
- # def defeault_price(self):
- # price = self.base_price
- # price += self.core_price
- # price += self.memory_price
- # price += self.disk_size_price * 10
- # return price
-
- def get_serialized_data(self):
- return {
- 'description': self.description,
- 'core_price': self.core_price,
- 'disk_size_price': self.disk_size_price,
- 'memory_price': self.memory_price,
- 'id': self.id,
- 'final_price': self.final_price,
- 'cores': self.cores,
- 'memory': self.memory,
- 'disk_size': self.disk_size
-
- }
-
- @classmethod
- def get_vm_templates(self, user):
- opennebula_client = OpenNebulaManager(
- email=user.email,
- password=user.password,
- )
-
- templates = opennebula_client.get_vm_templates()
- for template in templates:
- print(OpenNebulaManager.parse_vm(template))
- return templates
-
-
-class VirtualMachinePlan(AssignPermissionsMixin, models.Model):
-
- PENDING_STATUS = 'pending'
- ONLINE_STATUS = 'online'
- CANCELED_STATUS = 'canceled'
-
- VM_STATUS_CHOICES = (
- (PENDING_STATUS, 'Pending for activation'),
- (ONLINE_STATUS, 'Online'),
- (CANCELED_STATUS, 'Canceled')
- )
-
- # DJANGO = 'django'
- # RAILS = 'rails'
- # NODEJS = 'nodejs'
-
- # VM_CONFIGURATION = (
- # (DJANGO, 'Ubuntu 14.04, Django'),
- # (RAILS, 'Ubuntu 14.04, Rails'),
- # (NODEJS, 'Debian, NodeJS'),
- # )
-
- VM_CONFIGURATION = (
- ('debian', 'Debian 8'),
- ('ubuntu', 'Ubuntu 16.06'),
- ('devuan', 'Devuan 1'),
- ('centos', 'CentOS 7')
- )
-
- permissions = ('view_virtualmachineplan',
- 'cancel_virtualmachineplan',
- 'change_virtualmachineplan')
-
- cores = models.IntegerField()
- memory = models.IntegerField()
- disk_size = models.IntegerField()
- vm_type = models.ForeignKey(VirtualMachineType, null=True)
- price = models.FloatField()
- public_key = models.TextField(blank=True)
- status = models.CharField(max_length=20, choices=VM_STATUS_CHOICES, default=PENDING_STATUS)
- ip = models.CharField(max_length=50, blank=True)
- configuration = models.CharField(max_length=20, choices=VM_CONFIGURATION)
- opennebula_id = models.IntegerField(null=True)
-
- objects = VMPlansManager()
-
- class Meta:
- permissions = (
- ('view_virtualmachineplan', 'View Virtual Machine Plan'),
- ('cancel_virtualmachineplan', 'Cancel Virtual Machine Plan'),
- )
-
- def __str__(self):
- return self.name
-
- # @cached_property
- # def hosting_company_name(self):
- # return self.vm_type.get_hosting_company_display()
-
- # @cached_property
- # def location(self):
- # return self.vm_type.get_location_display()
-
- @cached_property
- def name(self):
- name = 'vm-%s' % self.id
- return name
-
- @cached_property
- def notifications(self):
- stripe_customer = StripeCustomer.objects.get(hostingorder__vm_plan=self)
- backend = stored_messages_settings.STORAGE_BACKEND()
- messages = backend.inbox_list(stripe_customer.user)
- return messages
-
- @classmethod
- def create(cls, data, user):
- instance = cls.objects.create(**data)
- instance.assign_permissions(user)
- return instance
-
- def cancel_plan(self, vm_id):
- self.status = self.CANCELED_STATUS
- self.save(update_fields=['status'])
-
- @classmethod
- def terminate_opennebula_vm(self, user, vm_id):
-
- opennebula_client = OpenNebulaManager(
- user.email,
- user.password,
- )
-
- return opennebula_client.terminate_vm(vm_id)
-
-
- @classmethod
- def create_opennebula_vm(self, user, specs):
- # import pdb
- # pdb.set_trace()
-
-
- # Init opennebula manager using given user
- opennebula_client = OpenNebulaManager(
- user.email,
- user.password,
- )
-
- # Create a vm in opennebula using given specs
- vm = opennebula_client.create_vm(specs)
- return vm
-
- @classmethod
- def get_vm(self, user, vm_id):
- # Get opennebula client
- opennebula_client = OpenNebulaManager(
- email=user.email,
- password=user.password,
- )
-
- # Get vm given the id
- vm = opennebula_client.get_vm(
- user.email,
- vm_id
- )
-
- # Parse vm data
- vm_data = OpenNebulaManager.parse_vm(vm)
-
- return vm_data
-
- @classmethod
- def get_vms(self, user):
-
- # Get opennebula client
- opennebula_client = OpenNebulaManager(
- email=user.email,
- password=user.password,
- )
-
- # Get vm pool
- vm_pool = opennebula_client.get_vms(user.email)
-
- # Reset total price
- self.total_price = 0
- vms = []
- # Add vm in vm_pool to context
- for vm in vm_pool:
- vm_data = OpenNebulaManager.parse_vm(vm)
- vms.append(vm_data)
- # self.total_price += price
- # self.save()
- return vms
-
class HostingOrder(AssignPermissionsMixin, models.Model):
ORDER_APPROVED_STATUS = 'Approved'
ORDER_DECLINED_STATUS = 'Declined'
- vm_plan = models.ForeignKey(VirtualMachinePlan, related_name='hosting_orders')
+ vm_id = models.IntegerField(default=0)
customer = models.ForeignKey(StripeCustomer)
billing_address = models.ForeignKey(BillingAddress)
created_at = models.DateTimeField(auto_now_add=True)
@@ -272,6 +37,7 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
last4 = models.CharField(max_length=4)
cc_brand = models.CharField(max_length=10)
stripe_charge_id = models.CharField(max_length=100, null=True)
+ price = models.FloatField()
permissions = ('view_hostingorder',)
@@ -288,9 +54,13 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
return self.ORDER_APPROVED_STATUS if self.approved else self.ORDER_DECLINED_STATUS
@classmethod
- def create(cls, vm_plan=None, customer=None, billing_address=None):
- instance = cls.objects.create(vm_plan=vm_plan, customer=customer,
- billing_address=billing_address)
+ def create(cls, price=None, vm_id=None, customer=None, billing_address=None):
+ instance = cls.objects.create(
+ price=price,
+ vm_id=vm_id,
+ customer=customer,
+ billing_address=billing_address
+ )
instance.assign_permissions(customer.user)
return instance
@@ -336,17 +106,6 @@ class UserHostingKey(models.Model):
# self.save(update_fields=['public_key'])
return private_key, public_key
-
-class ManageVM(models.Model):
- def has_add_permission(self, request):
- return False
-
- def has_delete_permission(self, request, obj=None):
- return False
-
- class Meta:
- managed = False
-
class HostingBill(AssignPermissionsMixin, models.Model):
customer = models.ForeignKey(StripeCustomer)
billing_address = models.ForeignKey(BillingAddress)
@@ -367,32 +126,3 @@ class HostingBill(AssignPermissionsMixin, models.Model):
instance = cls.objects.create(customer=customer, billing_address=billing_address)
return instance
- def get_vms(self):
- email = self.customer.user.email
- # Get opennebula client
- opennebula_client = OpenNebulaManager(create_user=False)
-
- # Get vm pool
- vm_pool = opennebula_client.get_vms(email)
-
- # Reset total price
- self.total_price = 0
- vms = []
- # Add vm in vm_pool to context
- for vm in vm_pool:
- vm_data = OpenNebulaManager.parse_vm(vm)
- self.total_price += vm_data['price']
- vms.append(vm_data)
- self.save()
- return vms
-
-
-
-def get_user_opennebula_password():
- '''
- TODO: Implement the way we obtain the user's opennebula password
- '''
- pw = os.environ.get('OPENNEBULA_USER_PW')
- if pw is None:
- raise Exception("Define OPENNEBULA_USER_PW env variable")
- return pw
diff --git a/hosting/templates/hosting/bill_detail.html b/hosting/templates/hosting/bill_detail.html
index 2d7f04b4..9e92d0e9 100644
--- a/hosting/templates/hosting/bill_detail.html
+++ b/hosting/templates/hosting/bill_detail.html
@@ -78,7 +78,7 @@
- {% trans "CH02 ............" %}
+ {% trans "CH02 0900 0000 6071 8848 8%}
{% trans "POFICHBEXXX" %}
diff --git a/hosting/templates/hosting/create_virtual_machine.html b/hosting/templates/hosting/create_virtual_machine.html
index 5d67b305..3a68421e 100644
--- a/hosting/templates/hosting/create_virtual_machine.html
+++ b/hosting/templates/hosting/create_virtual_machine.html
@@ -12,15 +12,19 @@
{% csrf_token %}
Select VM:
-
- {% for vm in vm_types %}
+
+ {% for template in templates %}
- CORE: {{vm.cores}}, RAM: {{vm.memory}}, SSD: {{vm.disk_size}}
+
+ CORE: {{template.cores}},
+ RAM: {{template.memory}} GiB,
+ SSD: {{template.disk_size}} GiB
+
{% endfor %}
-
-{%endblock%}
\ No newline at end of file
+{%endblock%}
diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html
index 5eb9bac1..868680aa 100644
--- a/hosting/templates/hosting/order_detail.html
+++ b/hosting/templates/hosting/order_detail.html
@@ -49,17 +49,13 @@
{% trans "Order summary"%}
-
{% trans "Type"%} {{order.vm_plan.hosting_company_name}}
+
{% trans "Cores"%} {{vm.cores}}
-
{% trans "Configuration"%} {{order.vm_plan.get_configuration_display}}
+
{% trans "Memory"%} {{vm.memory}} GiB
-
{% trans "Cores"%} {{order.vm_plan.cores}}
+
{% trans "Disk space"%} {{vm.disk_size}} GiB
-
{% trans "Memory"%} {{order.vm_plan.memory}} GiB
-
-
{% trans "Disk space"%} {{order.vm_plan.disk_size}} GiB
-
-
{% trans "Total"%} {{order.vm_plan.price}} CHF
+
{% trans "Total"%} {{vm.price}} CHF
{% url 'hosting:payment' as payment_url %}
diff --git a/hosting/templates/hosting/payment.html b/hosting/templates/hosting/payment.html
index 90da3870..bb80d566 100644
--- a/hosting/templates/hosting/payment.html
+++ b/hosting/templates/hosting/payment.html
@@ -100,15 +100,14 @@
-
Cores {{request.session.vm_specs.cores}}
+
Cores {{request.session.template.cores}}
-
Configuration {{request.session.vm_specs.configuration_display}}
-
-
Memory {{request.session.vm_specs.memory}} GiB
+
Memory {{request.session.template.memory}} GiB
-
Disk space {{request.session.vm_specs.disk_size}} GiB
+
Disk space {{request.session.template.disk_size}} GiB
-
Total {{request.session.vm_specs.final_price}} CHF
+
Total {{request.session.template.price }} CHF
diff --git a/hosting/templates/hosting/virtual_machine_detail.html b/hosting/templates/hosting/virtual_machine_detail.html
index 04c50279..e2f38d60 100644
--- a/hosting/templates/hosting/virtual_machine_detail.html
+++ b/hosting/templates/hosting/virtual_machine_detail.html
@@ -25,12 +25,6 @@
{% trans "Billing"%}
-
-
-
- {% trans "Orders"%}
-
-
{% trans "Status"%}
@@ -109,56 +103,22 @@
-
-
-
-
- Orders
-
-
-
- #
- {% trans "Date"%}
- {% trans "Amount"%}
- {% trans "Status"%}
-
-
-
-
- {% for order in virtual_machine.hosting_orders.all %}
-
- {{order.id}}
- {{order.created_at}}
- {{order.vm_plan.price}} CHF
- {% if order.approved %}
- {% trans "Approved"%}
- {% else%}
- {% trans "Declined"%}
- {% endif%}
-
-
- {% trans "View Detail"%}
-
-
- {% endfor %}
-
-
-
-
-
@@ -166,11 +126,12 @@
-
- {% trans "Terminate Virtual Machine"%}
+ {% trans "Terminate Virtual Machine"%}
@@ -194,7 +155,7 @@
{% trans "Terminate your Virtual Machine"%}
- {% trans "Are you sure do you want to cancel your Virtual Machine "%} {{vm.virtual_machine}} {% trans "plan?"%}
+ {% trans "Are you sure do you want to cancel your Virtual Machine "%} {{virtual_machine.name}} {% trans "plan?"%}
{%endblock%}
-
-
-
-
-
-
-
-
-
diff --git a/hosting/templates/hosting/virtual_machines.html b/hosting/templates/hosting/virtual_machines.html
index 7039964e..bb99c5e1 100644
--- a/hosting/templates/hosting/virtual_machines.html
+++ b/hosting/templates/hosting/virtual_machines.html
@@ -30,15 +30,15 @@
- {% for vm in vms_opennebula %}
+ {% for vm in vms %}
- {{vm.name}}
- {{vm.price|floatformat:2}} CHF
+ {{vm.vm_id}}
+ {{vm.price}} CHF
{% if vm.state == 'ACTIVE' %}
{{vm.state}}
- {% elif vm.state == 'POWEROFF' %}
+ {% elif vm.state == 'FAILED' %}
{{vm.state}}
{% else %}
{{vm.state}}
@@ -46,7 +46,8 @@
- {% trans "View Detail"%}
+ {% trans "View Detail"%}
{% endfor %}
@@ -76,4 +77,4 @@
-{%endblock%}
\ No newline at end of file
+{%endblock%}
diff --git a/hosting/views.py b/hosting/views.py
index 8f76c167..b292ce45 100644
--- a/hosting/views.py
+++ b/hosting/views.py
@@ -20,16 +20,18 @@ from stored_messages.models import Message
from stored_messages.api import mark_read
-
from membership.models import CustomUser, StripeCustomer
from utils.stripe_utils import StripeUtils
from utils.forms import BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
from utils.mailer import BaseEmail
-from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, HostingBill, UserHostingKey
+from .models import HostingOrder, HostingBill, UserHostingKey
from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyForm
from .mixins import ProcessVMSelectionMixin
-from .opennebula_functions import HostingManageVMAdmin, OpenNebulaManager
+
+from opennebula_api.models import OpenNebulaManager
+from opennebula_api.serializers import VirtualMachineSerializer,\
+ VirtualMachineTemplateSerializer
from oca.exceptions import OpenNebulaException
from oca.pool import WrongNameError
@@ -387,57 +389,26 @@ class PaymentVMView(LoginRequiredMixin, FormView):
context = self.get_context_data()
- specifications = request.session.get('vm_specs')
+ specifications = request.session.get('template')
- vm_template = specifications.get('vm_template', 1)
+ vm_template_id = specifications.get('id', 1)
- vm_type = VirtualMachineType.objects.get(id=vm_template)
-
- specs = vm_type.get_specs()
-
- final_price = vm_type.calculate_price()
-
- plan_data = {
- 'vm_type': vm_type,
- 'configuration': specifications.get(
- 'configuration',
- 'django'
- ),
- 'price': final_price
- }
-
- plan_data.update(specs)
+ final_price = specifications.get('price', 1)
token = form.cleaned_data.get('token')
+ owner = self.request.user
+
# Get or create stripe customer
- customer = StripeCustomer.get_or_create(email=self.request.user.email,
+ customer = StripeCustomer.get_or_create(email=owner.email,
token=token)
if not customer:
form.add_error("__all__", "Invalid credit card")
return self.render_to_response(self.get_context_data(form=form))
- # Create Virtual Machine Plan
- plan = VirtualMachinePlan.create(plan_data, request.user)
-
# Create Billing Address
billing_address = form.save()
- # Create Billing Address for User if he does not have one
- if not customer.user.billing_addresses.count():
- billing_address_data.update({
- 'user': customer.user.id
- })
- billing_address_user_form = UserBillingAddressForm(billing_address_data)
- billing_address_user_form.is_valid()
- billing_address_user_form.save()
-
- # Create a Hosting Order
- order = HostingOrder.create(vm_plan=plan, customer=customer,
- billing_address=billing_address)
- # Create a Hosting Bill
- bill = HostingBill.create(customer=customer, billing_address=billing_address)
-
# Make stripe charge to a customer
stripe_utils = StripeUtils()
charge_response = stripe_utils.make_charge(amount=final_price,
@@ -454,11 +425,11 @@ class PaymentVMView(LoginRequiredMixin, FormView):
charge = charge_response.get('response_object')
- # Associate an order with a stripe payment
- order.set_stripe_charge(charge)
-
- # If the Stripe payment was successed, set order status approved
- order.set_approved()
+ # Create OpenNebulaManager
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user=True)
+ template = manager.get_template(vm_template_id)
# Get user ssh key
try:
@@ -466,26 +437,46 @@ class PaymentVMView(LoginRequiredMixin, FormView):
user=self.request.user
)
- # Add ssh_key to specs
- specs.update({
- 'ssh_key': user_key.public_key
- })
-
except UserHostingKey.DoesNotExist:
pass
# Create a vm using logged user
- opennebula_vm_id = VirtualMachinePlan.create_opennebula_vm(
- self.request.user,
- specs
+ vm_id = manager.create_vm(
+ vm_template_id,
+ ssh_key=user_key.public_key
)
- plan.opennebula_id = opennebula_vm_id
- plan.save()
+ # Create a Hosting Order
+ order = HostingOrder.create(
+ price=final_price,
+ vm_id=vm_id,
+ customer=customer,
+ billing_address=billing_address
+ )
+
+ # Create a Hosting Bill
+ bill = HostingBill.create(customer=customer, billing_address=billing_address)
+
+ # Create Billing Address for User if he does not have one
+ if not customer.user.billing_addresses.count():
+ billing_address_data.update({
+ 'user': customer.user.id
+ })
+ billing_address_user_form = UserBillingAddressForm(billing_address_data)
+ billing_address_user_form.is_valid()
+ billing_address_user_form.save()
+
+ # Associate an order with a stripe payment
+ order.set_stripe_charge(charge)
+
+ # If the Stripe payment was successed, set order status approved
+ order.set_approved()
+
+ vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data
# Send notification to ungleich as soon as VM has been booked
context = {
- 'vm': plan,
+ 'vm': vm,
'order': order,
'base_url': "{0}://{1}".format(request.scheme, request.get_host())
@@ -512,6 +503,18 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai
permission_required = ['view_hostingorder']
model = HostingOrder
+ def get_context_data(self, **kwargs):
+ # Get context
+ context = super(DetailView, self).get_context_data(**kwargs)
+ obj = self.get_object()
+ owner = self.request.user
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user=True)
+ vm = manager.get_vm(obj.vm_id)
+ context['vm'] = VirtualMachineSerializer(vm).data
+ return context
+
class OrdersHostingListView(LoginRequiredMixin, ListView):
template_name = "hosting/orders.html"
@@ -537,24 +540,17 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView):
template_name = "hosting/virtual_machines.html"
login_url = reverse_lazy('hosting:login')
context_object_name = "vms"
- model = VirtualMachinePlan
paginate_by = 10
ordering = '-id'
- def get_context_data(self, **kwargs):
- context = super(VirtualMachinesPlanListView, self).get_context_data(**kwargs)
- context.update({
- 'vms_opennebula': VirtualMachinePlan.get_vms(self.request.user)
- })
- return context
-
def get_queryset(self):
- # hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin)
- # print(hosting_admin.show_vms_view(self.request))
- # print(VirtualMachinePlan.get_vms(self.request.user.))
- user = self.request.user
- self.queryset = VirtualMachinePlan.objects.active(user)
- return super(VirtualMachinesPlanListView, self).get_queryset()
+ owner = self.request.user
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user=True)
+ queryset = manager.get_vms()
+ serializer = VirtualMachineSerializer(queryset, many=True)
+ return serializer.data
class CreateVirtualMachinesView(LoginRequiredMixin, View):
@@ -574,107 +570,70 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
)
return HttpResponseRedirect(reverse('hosting:key_pair'))
+ #TODO: Replace with OpenNebulaManager.get_apps
+ templates = OpenNebulaManager().get_templates()
+ data = VirtualMachineTemplateSerializer(templates, many=True).data
+
context = {
- 'vm_types': VirtualMachineType.get_serialized_vm_types(),
- 'configuration_options': VirtualMachinePlan.VM_CONFIGURATION
+ 'templates': data,
}
# context = {}
return render(request, self.template_name, context)
def post(self, request):
- configuration = request.POST.get('configuration')
- configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration)
- vm_template = request.POST.get('vm_template')
- vm_type = VirtualMachineType.objects.get(id=vm_template)
- vm_specs = vm_type.get_specs()
- vm_specs.update({
- 'configuration_display': configuration_display,
- 'configuration': configuration,
- 'final_price': vm_type.final_price,
- 'vm_template': vm_template
- })
- request.session['vm_specs'] = vm_specs
+ template_id = int(request.POST.get('vm_template_id'))
+ template = OpenNebulaManager().get_template(template_id)
+ data = VirtualMachineTemplateSerializer(template).data
+ request.session['template'] = data
return redirect(reverse('hosting:payment'))
- # def get_queryset(self):
- # # hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin)
- # # print(hosting_admin.show_vms(self.request))
- # user = self.request.user
- # self.queryset = VirtualMachinePlan.objects.active(user)
- # return super(VirtualMachinesPlanListView, self).get_queryset()
-
-class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
+class VirtualMachineView(LoginRequiredMixin, View):
template_name = "hosting/virtual_machine_detail.html"
login_url = reverse_lazy('hosting:login')
- # model = VirtualMachinePlan
- # context_object_name = "virtual_machine"
- permission_required = []
- # fields = '__all__'
-
- # def get_context_data(self, **kwargs):
- # vm_plan = get_object()
- # context = super(VirtualMachineView, self).get_context_data(**kwargs)
- # context.update({
- # 'opennebula_vm': VirtualMachinePlan.get_vm(
- # self.request.user.email,
- # opennebula_id
- # )
- # })
- # return context
-
- # def get_object(self, queryset=None):
- # # if queryset is None:
- # # queryset = self.get_queryset()
- # # Next, try looking up by primary key.
- # vm_id = self.kwargs.get(self.pk_url_kwarg)
- # try:
- # return VirtualMachinePlan.get_vm(
- # self.request.user.email,
- # vm_id
- # )
- # except Exception as error:
- # raise Http404()
def get_object(self):
- opennebula_vm_id = self.kwargs.get('pk')
- opennebula_vm = None
+ owner = self.request.user
+ vm = None
+ manager = OpenNebulaManager(
+ email=owner.email,
+ password=owner.password,
+ create_user=True
+ )
+ vm_id = self.kwargs.get('pk')
try:
- opennebula_vm = VirtualMachinePlan.objects.get(opennebula_id=opennebula_vm_id)
+ vm = manager.get_vm(vm_id)
except Exception as error:
print(error)
raise Http404()
- return opennebula_vm
+ return vm
def get_success_url(self):
final_url = reverse('hosting:virtual_machines')
return final_url
def get(self, request, *args, **kwargs):
- opennebula_vm_id = self.kwargs.get('pk')
- try:
- opennebula_vm = VirtualMachinePlan.get_vm(
- self.request.user,
- opennebula_vm_id
- )
- except Exception as error:
- print(error)
- raise Http404()
-
+ vm = self.get_object()
+ serializer = VirtualMachineSerializer(vm)
context = {
- 'virtual_machine': opennebula_vm,
+ 'virtual_machine': serializer.data,
}
- # context = {}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
+ owner = self.request.user
vm = self.get_object()
opennebula_vm_id = self.kwargs.get('pk')
- terminated = VirtualMachinePlan.terminate_opennebula_vm(
- self.request.user,
- opennebula_vm_id
+ manager = OpenNebulaManager(
+ email=owner.email,
+ password=owner.password,
+ create_user=True
+ )
+
+ terminated = manager.delete_vm(
+ vm.id
)
if not terminated:
@@ -684,8 +643,6 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
)
return HttpResponseRedirect(self.get_success_url())
- #vm.cancel_plan()
-
context = {
'vm': vm,
'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
@@ -735,10 +692,14 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV
def get_context_data(self, **kwargs):
# Get context
context = super(DetailView, self).get_context_data(**kwargs)
+
+ owner = self.request.user
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user=True)
# Get vms
- try:
- context['vms'] = self.get_object().get_vms()
- except:
- pass
+ queryset = manager.get_vms()
+ vms = VirtualMachineSerializer(queryset, many=True).data
+ context['vms'] = vms
return context
diff --git a/opennebula_api/migrations/0001_initial.py b/opennebula_api/migrations/0001_initial.py
deleted file mode 100644
index 78747cd2..00000000
--- a/opennebula_api/migrations/0001_initial.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.9.4 on 2017-05-09 14:36
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
- initial = True
-
- dependencies = [
- ]
-
- operations = [
- migrations.CreateModel(
- name='VirtualMachine',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('opennebula_id', models.IntegerField()),
- ],
- ),
- migrations.CreateModel(
- name='VirtualMachineTemplate',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('opennebula_id', models.IntegerField()),
- ('base_price', models.FloatField()),
- ('memory_price', models.FloatField()),
- ('core_price', models.FloatField()),
- ('disk_size_price', models.FloatField()),
- ],
- ),
- migrations.AddField(
- model_name='virtualmachine',
- name='template',
- field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='opennebula_api.VirtualMachineTemplate'),
- ),
- ]
diff --git a/opennebula_api/models.py b/opennebula_api/models.py
index 6a7ba2fc..8c7743b4 100644
--- a/opennebula_api/models.py
+++ b/opennebula_api/models.py
@@ -1,110 +1,14 @@
import oca
import socket
+import logging
+
-from django.db import models
from django.conf import settings
+from django.utils.functional import cached_property
from oca.pool import WrongNameError
-
-class VirtualMachineTemplate(models.Model):
- """This class represents an opennebula template."""
- opennebula_id = models.IntegerField()
- base_price = models.FloatField()
- memory_price = models.FloatField()
- core_price = models.FloatField()
- disk_size_price = models.FloatField()
-
- def calculate_price(self):
- template = OpenNebulaManager()._get_template(self.opennebula_id).template
-
- price = int(template.vcpu) * self.core_price
- price += int(template.memory) / 1024 * self.memory_price
- try:
- price += int(template.disk.size) / 1024 * self.disk_size_price
- except AttributeError:
- for disk in template.disks:
- price += int(disk.size) / 1024 * self.disk_size_price
- return price
-
- def get_name(self):
-
- template = OpenNebulaManager()._get_template(template_id=self.opennebula_id)
- return template.name
-
- def get_cores(self):
-
- template = OpenNebulaManager()._get_template(template_id=self.opennebula_id).template
- return int(template.vcpu)
-
- def get_disk_size(self):
-
- template = OpenNebulaManager()._get_template(template_id=self.opennebula_id).template
- disk_size = 0
- for disk in template.disks:
- disk_size += int(disk.size)
- return disk_size / 1024
-
- def get_memory(self):
-
- template = OpenNebulaManager()._get_template(template_id=self.opennebula_id).template
- return int(template.memory) / 1024
-
-class VirtualMachine(models.Model):
- """This class represents an opennebula virtual machine."""
- opennebula_id = models.IntegerField()
- vm_template = models.ForeignKey(VirtualMachineTemplate)
-
- VM_STATE = {
- '0': 'INIT',
- '1': 'PENDING',
- '2': 'HOLD',
- '3': 'ACTIVE',
- '4': 'STOPPED',
- '5': 'SUSPENDED',
- '6': 'DONE',
- '8': 'POWEROFF',
- '9': 'UNDEPLOYED',
- '10': 'CLONING',
- '11': 'CLONING_FAILURE',
- }
-
- def get_name(self):
-
- vm = OpenNebulaManager()._get_vm(vm_id=self.opennebula_id)
- return vm.name
-
- def get_cores(self):
-
- return self.vm_template.get_cores()
-
- def get_disk_size(self):
-
- return self.vm_template.get_disk_size()
-
- def get_memory(self):
-
- return self.vm_template.get_memory()
-
- def get_id(self):
-
- vm = OpenNebulaManager()._get_vm(vm_id=self.opennebula_id)
- return vm.id
-
- def get_ip(self):
-
- vm = OpenNebulaManager()._get_vm(vm_id=self.opennebula_id)
- try:
- return vm.user_template.ungleich_public_ip
- except AttributeError:
- return '-'
-
- def get_state(self):
-
- vm = OpenNebulaManager()._get_vm(vm_id=self.opennebula_id)
- return self.VM_STATE.get(str(vm.state))
-
- def get_price(self):
- return self.vm_template.calculate_price()
+from oca.exceptions import OpenNebulaException
+logger = logging.getLogger(__name__)
class OpenNebulaManager():
"""This class represents an opennebula manager."""
@@ -175,8 +79,13 @@ class OpenNebulaManager():
def _get_vm_pool(self):
try:
- vm_pool = oca.VirtualMachinePool(self.oneadmin_client)
- vm_pool.info()
+ vm_pool = oca.VirtualMachinePool(self.client)
+ vm_pool.info()
+ except AttributeError:
+ print('Could not connect via client, using oneadmin instead')
+ vm_pool = oca.VirtualMachinePool(self.oneadmin_client)
+ vm_pool.info(filter=-2)
+
#TODO: Replace with logger
except ConnectionRefusedError:
print('Could not connect to host: {host} via protocol {protocol}'.format(
@@ -186,19 +95,25 @@ class OpenNebulaManager():
raise ConnectionRefusedError
return vm_pool
+ def get_vms(self):
+ return self._get_vm_pool()
- def _get_vm(self, vm_id):
+ def get_vm(self, vm_id):
vm_pool = self._get_vm_pool()
- # Get virtual machines from all users
- vm_pool.info(filter=-2)
- return vm_pool.get_by_id(vm_id)
+ return vm_pool.get_by_id(int(vm_id))
- def create_vm(self, template_id):
- template_pool = self._get_template_pool()
-
- template = template_pool.get_by_id(template_id)
-
- vm_id = template.instantiate()
+ #TODO: get app with id
+ def create_vm(self, template_id, app_id=None, ssh_key=None):
+ extra_template = "{ssh_key} ".format(
+ ssh_key=ssh_key
+ )
+ vm_id = self.oneadmin_client.call(
+ oca.VmTemplate.METHODS['instantiate'],
+ template_id,
+ '',
+ False,
+ extra_template
+ )
try:
self.oneadmin_client.call(
oca.VirtualMachine.METHODS['chown'],
@@ -207,12 +122,33 @@ class OpenNebulaManager():
self.opennebula_user.group_ids[0]
)
except AttributeError:
- pass
+ print('Could not change owner, opennebula_user is not set.')
return vm_id
def delete_vm(self, vm_id):
- vm = self._get_vm(vm_id)
- vm.delete()
+ TERMINATE_ACTION = 'terminate'
+ vm_terminated = False
+ try:
+ self.oneadmin_client.call(
+ oca.VirtualMachine.METHODS['action'],
+ TERMINATE_ACTION,
+ int(vm_id),
+ )
+ vm_terminated = True
+ except socket.timeout as socket_err:
+ logger.info("Socket timeout error: {0}".format(socket_err))
+ print("Socket timeout error: {0}".format(socket_err))
+ except OpenNebulaException as opennebula_err:
+ logger.info("OpenNebulaException error: {0}".format(opennebula_err))
+ print("OpenNebulaException error: {0}".format(opennebula_err))
+ except OSError as os_err:
+ logger.info("OSError : {0}".format(os_err))
+ print("OSError : {0}".format(os_err))
+ except ValueError as value_err:
+ logger.info("ValueError : {0}".format(value_err))
+ print("ValueError : {0}".format(value_err))
+
+ return vm_terminated
def _get_template_pool(self):
try:
@@ -227,19 +163,31 @@ class OpenNebulaManager():
raise ConnectionRefusedError
return template_pool
- def _get_template(self, template_id):
+ def get_templates(self):
+ public_templates = [
+ template
+ for template in self._get_template_pool()
+ if 'public-' in template.name
+ ]
+ return public_templates
+ def get_template(self, template_id):
template_pool = self._get_template_pool()
return template_pool.get_by_id(template_id)
- def create_template(self, name, cores, memory, disk_size):
+ def create_template(self, name, cores, memory, disk_size, core_price, memory_price,
+ disk_size_price, ssh='' ):
"""Create and add a new template to opennebula.
:param name: A string representation describing the template.
Used as label in view.
:param cores: Amount of virtual cpu cores for the VM.
- :param memory: Amount of RAM for the VM (MB)
- :param disk_size: Amount of disk space for VM (MB)
+ :param memory: Amount of RAM for the VM (GB)
+ :param disk_size: Amount of disk space for VM (GB)
+ :param core_price: Price of virtual cpu for the VM per core.
+ :param memory_price: Price of RAM for the VM per GB
+ :param disk_size_price: Price of disk space for VM per GB
+ :param ssh: User public ssh key
"""
template_string_formatter = """
{name}
@@ -251,6 +199,10 @@ class OpenNebulaManager():
{size}
vd
+ {cpu_cost}
+ {memory_cost}
+ {disk_cost}
+ {ssh}
"""
template_id = oca.VmTemplate.allocate(
@@ -260,7 +212,12 @@ class OpenNebulaManager():
vcpu=cores,
cpu=0.1*cores,
size=1024 * disk_size,
- memory=1024 * memory
+ memory=1024 * memory,
+ # * 10 because we set cpu to *0.1
+ cpu_cost=10*core_price,
+ memory_cost=memory_price,
+ disk_cost=disk_size_price,
+ ssh=ssh
)
)
@@ -269,5 +226,3 @@ class OpenNebulaManager():
def delete_template(self, template_id):
self.oneadmin_client.call(oca.VmTemplate.METHODS['delete'], template_id, False)
-
-
diff --git a/opennebula_api/serializers.py b/opennebula_api/serializers.py
index e8ff33bd..b73682e6 100644
--- a/opennebula_api/serializers.py
+++ b/opennebula_api/serializers.py
@@ -3,91 +3,117 @@ import oca
from rest_framework import serializers
from oca import OpenNebulaException
+from oca.template import VmTemplate
-from .models import VirtualMachine, VirtualMachineTemplate, OpenNebulaManager
+from .models import OpenNebulaManager
-class VirtualMachineTemplateSerializer(serializers.ModelSerializer):
+class VirtualMachineTemplateSerializer(serializers.Serializer):
"""Serializer to map the virtual machine template instance into JSON format."""
- cores = serializers.IntegerField(source='get_cores')
- name = serializers.CharField(source='get_name')
- disk_size = serializers.IntegerField(source='get_disk_size')
- memory = serializers.IntegerField(source='get_memory')
+ id = serializers.IntegerField(read_only=True)
+ name = serializers.CharField()
+ cores = serializers.IntegerField(source='template.vcpu')
+ disk = serializers.IntegerField(write_only=True)
+ disk_size = serializers.SerializerMethodField()
+ memory = serializers.SerializerMethodField()
+ core_price = serializers.FloatField(source='template.cpu_cost')
+ disk_size_price = serializers.FloatField(source='template.disk_cost')
+ memory_price = serializers.FloatField(source='template.memory_cost')
+ price = serializers.SerializerMethodField()
- class Meta:
- model = VirtualMachineTemplate
- fields = ('id', 'name', 'cores', 'memory', 'disk_size', 'base_price',
- 'core_price', 'memory_price', 'disk_size_price', 'opennebula_id')
- read_only_fields = ('opennebula_id', )
-
- def validate(self, data):
- # Create the opennebula model
- cores = data.pop('get_cores')
- name = data.pop('get_name')
- disk_size = data.pop('get_disk_size')
- memory = data.pop('get_memory')
+ def create(self, validated_data):
+ data = validated_data
+ template = data.pop('template')
+ cores = template.pop('vcpu')
+ name = data.pop('name')
+ disk_size = data.pop('disk')
+ memory = template.pop('memory')
+ core_price = template.pop('cpu_cost')
+ memory_price = template.pop('memory_cost')
+ disk_size_price = template.pop('disk_cost')
manager = OpenNebulaManager(create_user = False)
try:
opennebula_id = manager.create_template(name=name, cores=cores,
memory=memory,
- disk_size=disk_size)
- data.update({'opennebula_id':opennebula_id})
+ disk_size=disk_size,
+ core_price=core_price,
+ disk_size_price=disk_size_price,
+ memory_price=memory_price)
except OpenNebulaException as err:
raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
- return data
+ return manager.get_template(template_id=opennebula_id)
- def create(self, validated_data):
- return VirtualMachineTemplate.objects.create(**validated_data)
+ def get_disk_size(self, obj):
+ template = obj.template
+ disk_size = 0
+ for disk in template.disks:
+ disk_size += int(disk.size)
+ return disk_size / 1024
-class TemplatePrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
- def display_value(self, instance):
- return 'Template: {}'.format(instance.get_name())
+ def get_price(self, obj):
+ template = obj.template
+ price = float(template.cpu) * float(template.cpu_cost)
+ price += (int(template.memory)/1024 * float(template.memory_cost))
+ for disk in template.disks:
+ price += int(disk.size)/1024 * float(template.disk_cost)
+ return price
-class VirtualMachineSerializer(serializers.ModelSerializer):
+ def get_memory(self, obj):
+ return int(obj.template.memory)/1024
+
+class VirtualMachineSerializer(serializers.Serializer):
"""Serializer to map the virtual machine instance into JSON format."""
- #TODO: Maybe we can change to template.get_cores
- cores = serializers.IntegerField(read_only=True, source='get_cores')
- name = serializers.CharField(read_only=True, source='get_name')
- disk_size = serializers.IntegerField(read_only=True, source='get_disk_size')
- memory = serializers.IntegerField(read_only=True, source='get_memory')
- #TODO: See if we can change to IPAddressField
- ip = serializers.CharField(read_only=True, source='get_ip')
- deploy_id = serializers.IntegerField(read_only=True, source='get_deploy_id')
- vm_id = serializers.IntegerField(read_only=True, source='get_vm_id')
- state = serializers.CharField(read_only=True, source='get_state')
- price = serializers.FloatField(read_only=True, source='get_price')
+ name = serializers.CharField(read_only=True)
+ cores = serializers.IntegerField(read_only=True, source='template.vcpu')
- vm_template = VirtualMachineTemplateSerializer(read_only=True)
+ disk_size = serializers.SerializerMethodField()
+ memory = serializers.SerializerMethodField()
+ ip = serializers.CharField(read_only=True,
+ source='user_template.ungleich_public_ip',
+ default='-')
+ vm_id = serializers.IntegerField(read_only=True, source='id')
+ state = serializers.CharField(read_only=True, source='str_state')
+ price = serializers.SerializerMethodField()
- vm_template_id = TemplatePrimaryKeyRelatedField(
- queryset=VirtualMachineTemplate.objects.all(),
- source='vm_template'
+ template_id = serializers.ChoiceField(
+ choices=[(key.id, key.name) for key in
+ OpenNebulaManager().get_templates()],
+ source='template.template_id',
+ write_only=True
)
- class Meta:
- model = VirtualMachine
- fields = ('id', 'opennebula_id', 'vm_template', 'vm_template_id', 'cores', 'name',
- 'disk_size', 'memory', 'ip', 'deploy_id', 'state', 'vm_id',
- 'price')
- read_only_fields = ('opennebula_id', )
+ def create(self, validated_data):
+ owner = validated_data['owner']
+ template_id = validated_data['template']['template_id']
- def validate(self, data):
- # Create the opennebula model
- manager = OpenNebulaManager(create_user = False)
-
try:
- template_id = data['vm_template'].opennebula_id
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user = True)
opennebula_id = manager.create_vm(template_id)
- data.update({'opennebula_id':opennebula_id})
except OpenNebulaException as err:
raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
- return data
+ return manager.get_vm(opennebula_id)
- def create(self, validated_data):
- return VirtualMachine.objects.create(**validated_data)
+ def get_memory(self, obj):
+ return int(obj.template.memory)/1024
+ def get_disk_size(self, obj):
+ template = obj.template
+ disk_size = 0
+ for disk in template.disks:
+ disk_size += int(disk.size)
+ return disk_size / 1024
+
+ def get_price(self, obj):
+ template = obj.template
+ price = float(template.cpu) * float(template.cpu_cost)
+ price += (int(template.memory)/1024 * float(template.memory_cost))
+ for disk in template.disks:
+ price += int(disk.size)/1024 * float(template.disk_cost)
+ return price
diff --git a/opennebula_api/urls.py b/opennebula_api/urls.py
new file mode 100644
index 00000000..be5bdbf2
--- /dev/null
+++ b/opennebula_api/urls.py
@@ -0,0 +1,18 @@
+from django.conf.urls import url, include
+from rest_framework.urlpatterns import format_suffix_patterns
+from .views import TemplateCreateView, TemplateDetailsView,\
+ VmCreateView, VmDetailsView
+
+urlpatterns = {
+ url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
+
+ url(r'^templates/$', TemplateCreateView.as_view(), name="template_create"),
+ url(r'^templates/(?P[0-9]+)/$', TemplateDetailsView.as_view(),
+ name="templates_details"),
+
+ url(r'^vms/$', VmCreateView.as_view(), name="vm_create"),
+ url(r'^vms/(?P[0-9]+)/$', VmDetailsView.as_view(),
+ name="vm_details"),
+}
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/opennebula_api/views.py b/opennebula_api/views.py
index 4cd237ae..20a28968 100644
--- a/opennebula_api/views.py
+++ b/opennebula_api/views.py
@@ -1,13 +1,29 @@
from rest_framework import generics
+from rest_framework import permissions
+
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.contrib.auth import authenticate, login
+
+
+from utils.views import LoginViewMixin
+from membership.models import CustomUser, StripeCustomer
+from guardian.mixins import PermissionRequiredMixin
from .serializers import VirtualMachineTemplateSerializer, \
VirtualMachineSerializer
-from .models import VirtualMachineTemplate, VirtualMachine, OpenNebulaManager
+from .models import OpenNebulaManager
+
class TemplateCreateView(generics.ListCreateAPIView):
- """This class defines the create behavior of our rest api."""
- queryset = VirtualMachineTemplate.objects.all()
+ """This class handles the GET and POST requests."""
+
serializer_class = VirtualMachineTemplateSerializer
+ permission_classes = (permissions.IsAuthenticated, permissions.IsAdminUser)
+
+ def get_queryset(self):
+ manager = OpenNebulaManager()
+ return manager.get_templates()
+
def perform_create(self, serializer):
"""Save the post data when creating a new template."""
@@ -16,20 +32,53 @@ class TemplateCreateView(generics.ListCreateAPIView):
class TemplateDetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests."""
- queryset = VirtualMachineTemplate.objects.all()
serializer_class = VirtualMachineTemplateSerializer
+ permission_classes = (permissions.IsAuthenticated)
+
+ def get_queryset(self):
+ manager = OpenNebulaManager()
+ return manager.get_templates()
class VmCreateView(generics.ListCreateAPIView):
- """This class defines the create behavior of our rest api."""
- queryset = VirtualMachine.objects.all()
+ """This class handles the GET and POST requests."""
serializer_class = VirtualMachineSerializer
+ permission_classes = (permissions.IsAuthenticated, )
+
+ def get_queryset(self):
+ owner = self.request.user
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user=True)
+ return manager.get_vms()
def perform_create(self, serializer):
"""Save the post data when creating a new template."""
- serializer.save()
+ serializer.save(owner=self.request.user)
class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests."""
+ permission_classes = (permissions.IsAuthenticated, )
- queryset = VirtualMachine.objects.all()
serializer_class = VirtualMachineSerializer
+
+ def get_queryset(self):
+ owner = self.request.user
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user=True)
+ return manager.get_vms()
+
+ def get_object(self):
+ owner = self.request.user
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user=True)
+ return manager.get_vm(self.kwargs.get('pk'))
+
+ def perform_destroy(self, instance):
+ owner = self.request.user
+ manager = OpenNebulaManager(email=owner.email,
+ password=owner.password,
+ create_user = True)
+ manager.delete_vm(instance.id)
+