2016-05-24 06:19:49 +00:00
|
|
|
import os
|
2016-04-23 07:22:44 +00:00
|
|
|
|
2015-05-27 10:21:30 +00:00
|
|
|
from django.db import models
|
2016-05-03 05:59:40 +00:00
|
|
|
from django.utils.functional import cached_property
|
2017-04-24 22:25:05 +00:00
|
|
|
|
|
|
|
from Crypto.PublicKey import RSA
|
2016-05-29 18:37:43 +00:00
|
|
|
from stored_messages.settings import stored_messages_settings
|
2016-05-24 06:19:49 +00:00
|
|
|
|
2016-05-29 18:37:43 +00:00
|
|
|
from membership.models import StripeCustomer
|
2017-04-24 22:07:50 +00:00
|
|
|
from utils.models import BillingAddress
|
2017-04-24 22:25:05 +00:00
|
|
|
from utils.mixins import AssignPermissionsMixin
|
2016-05-03 05:59:40 +00:00
|
|
|
from .managers import VMPlansManager
|
|
|
|
|
2016-04-18 00:52:19 +00:00
|
|
|
|
|
|
|
class VirtualMachineType(models.Model):
|
|
|
|
|
|
|
|
HETZNER_NUG = 'hetzner_nug'
|
|
|
|
HETZNER = 'hetzner'
|
|
|
|
HETZNER_R6 = 'hetzner_raid6'
|
|
|
|
HETZNER_G = 'hetzner_glusterfs'
|
|
|
|
BERN = 'bern'
|
2016-05-19 06:17:16 +00:00
|
|
|
DE_LOCATION = 'DE'
|
|
|
|
CH_LOCATION = 'CH'
|
2016-04-18 00:52:19 +00:00
|
|
|
|
|
|
|
HOSTING_TYPES = (
|
|
|
|
(HETZNER_NUG, 'Hetzner No Uptime Guarantee'),
|
|
|
|
(HETZNER, 'Hetzner'),
|
|
|
|
(HETZNER_R6, 'Hetzner Raid6'),
|
|
|
|
(HETZNER_G, 'Hetzner Glusterfs'),
|
|
|
|
(BERN, 'Bern'),
|
|
|
|
)
|
|
|
|
|
2016-05-19 06:17:16 +00:00
|
|
|
LOCATIONS_CHOICES = (
|
|
|
|
(DE_LOCATION, 'Germany'),
|
|
|
|
(CH_LOCATION, 'Switzerland'),
|
|
|
|
)
|
2016-06-07 05:29:22 +00:00
|
|
|
|
2016-04-18 00:52:19 +00:00
|
|
|
description = models.TextField()
|
|
|
|
base_price = models.FloatField()
|
|
|
|
memory_price = models.FloatField()
|
|
|
|
core_price = models.FloatField()
|
|
|
|
disk_size_price = models.FloatField()
|
2016-04-18 01:05:39 +00:00
|
|
|
hosting_company = models.CharField(max_length=30, choices=HOSTING_TYPES)
|
2016-05-19 06:17:16 +00:00
|
|
|
location = models.CharField(max_length=3, choices=LOCATIONS_CHOICES)
|
2016-04-18 01:05:39 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return "%s" % (self.get_hosting_company_display())
|
2016-04-18 00:52:19 +00:00
|
|
|
|
2016-04-19 06:04:15 +00:00
|
|
|
@classmethod
|
|
|
|
def get_serialized_vm_types(cls):
|
|
|
|
return [vm.get_serialized_data()
|
2016-04-20 06:03:32 +00:00
|
|
|
for vm in cls.objects.all()]
|
2016-04-23 07:22:44 +00:00
|
|
|
|
|
|
|
def calculate_price(self, specifications):
|
|
|
|
price = float(specifications['cores']) * self.core_price
|
|
|
|
price += float(specifications['memory']) * self.memory_price
|
|
|
|
price += float(specifications['disk_size']) * self.disk_size_price
|
|
|
|
price += self.base_price
|
|
|
|
return price
|
2016-04-19 06:04:15 +00:00
|
|
|
|
2016-04-20 06:03:32 +00:00
|
|
|
def defeault_price(self):
|
|
|
|
price = self.base_price
|
|
|
|
price += self.core_price
|
|
|
|
price += self.memory_price
|
|
|
|
price += self.disk_size_price * 10
|
|
|
|
return price
|
|
|
|
|
2016-04-18 00:52:19 +00:00
|
|
|
def get_serialized_data(self):
|
2016-04-19 06:04:15 +00:00
|
|
|
return {
|
|
|
|
'description': self.description,
|
|
|
|
'base_price': self.base_price,
|
|
|
|
'core_price': self.core_price,
|
|
|
|
'disk_size_price': self.disk_size_price,
|
|
|
|
'memory_price': self.memory_price,
|
|
|
|
'hosting_company_name': self.get_hosting_company_display(),
|
|
|
|
'hosting_company': self.hosting_company,
|
2016-04-20 06:03:32 +00:00
|
|
|
'default_price': self.defeault_price(),
|
2016-05-19 06:17:16 +00:00
|
|
|
'location_code': self.location,
|
|
|
|
'location': self.get_location_display(),
|
2016-04-19 06:04:15 +00:00
|
|
|
'id': self.id,
|
|
|
|
}
|
2016-04-23 07:22:44 +00:00
|
|
|
|
|
|
|
|
2016-06-26 19:50:48 +00:00
|
|
|
class VirtualMachinePlan(AssignPermissionsMixin, models.Model):
|
2016-05-27 05:51:10 +00:00
|
|
|
|
|
|
|
PENDING_STATUS = 'pending'
|
|
|
|
ONLINE_STATUS = 'online'
|
|
|
|
CANCELED_STATUS = 'canceled'
|
|
|
|
|
|
|
|
VM_STATUS_CHOICES = (
|
|
|
|
(PENDING_STATUS, 'Pending for activation'),
|
|
|
|
(ONLINE_STATUS, 'Online'),
|
|
|
|
(CANCELED_STATUS, 'Canceled')
|
|
|
|
)
|
|
|
|
|
2016-06-07 05:29:22 +00:00
|
|
|
DJANGO = 'django'
|
|
|
|
RAILS = 'rails'
|
|
|
|
NODEJS = 'nodejs'
|
|
|
|
|
|
|
|
VM_CONFIGURATION = (
|
|
|
|
(DJANGO, 'Ubuntu 14.04, Django'),
|
|
|
|
(RAILS, 'Ubuntu 14.04, Rails'),
|
|
|
|
(NODEJS, 'Debian, NodeJS'),
|
|
|
|
)
|
|
|
|
|
2016-07-11 03:08:51 +00:00
|
|
|
permissions = ('view_virtualmachineplan',
|
|
|
|
'cancel_virtualmachineplan',
|
|
|
|
'change_virtualmachineplan')
|
2016-06-26 19:50:48 +00:00
|
|
|
|
2016-04-23 07:22:44 +00:00
|
|
|
cores = models.IntegerField()
|
|
|
|
memory = models.IntegerField()
|
|
|
|
disk_size = models.IntegerField()
|
|
|
|
vm_type = models.ForeignKey(VirtualMachineType)
|
|
|
|
price = models.FloatField()
|
2016-06-07 05:29:22 +00:00
|
|
|
public_key = models.TextField(blank=True)
|
2016-05-27 05:51:10 +00:00
|
|
|
status = models.CharField(max_length=20, choices=VM_STATUS_CHOICES, default=PENDING_STATUS)
|
2016-06-07 05:29:22 +00:00
|
|
|
ip = models.CharField(max_length=50, blank=True)
|
|
|
|
configuration = models.CharField(max_length=20, choices=VM_CONFIGURATION)
|
2016-04-23 07:22:44 +00:00
|
|
|
|
2016-05-03 05:59:40 +00:00
|
|
|
objects = VMPlansManager()
|
|
|
|
|
2016-06-26 19:50:48 +00:00
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
('view_virtualmachineplan', 'View Virtual Machine Plan'),
|
|
|
|
('cancel_virtualmachineplan', 'Cancel Virtual Machine Plan'),
|
|
|
|
)
|
|
|
|
|
2016-05-14 06:42:42 +00:00
|
|
|
def __str__(self):
|
2016-06-03 05:07:47 +00:00
|
|
|
return self.name
|
2016-05-14 06:42:42 +00:00
|
|
|
|
2016-05-03 05:59:40 +00:00
|
|
|
@cached_property
|
|
|
|
def hosting_company_name(self):
|
|
|
|
return self.vm_type.get_hosting_company_display()
|
|
|
|
|
2016-05-27 05:51:10 +00:00
|
|
|
@cached_property
|
|
|
|
def location(self):
|
|
|
|
return self.vm_type.get_location_display()
|
|
|
|
|
2016-05-04 05:16:41 +00:00
|
|
|
@cached_property
|
|
|
|
def name(self):
|
|
|
|
name = 'vm-%s' % self.id
|
|
|
|
return name
|
|
|
|
|
2016-05-29 18:37:43 +00:00
|
|
|
@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
|
|
|
|
|
2016-04-23 07:22:44 +00:00
|
|
|
@classmethod
|
|
|
|
def create(cls, data, user):
|
|
|
|
instance = cls.objects.create(**data)
|
2016-06-26 19:50:48 +00:00
|
|
|
instance.assign_permissions(user)
|
2016-04-26 06:16:03 +00:00
|
|
|
return instance
|
|
|
|
|
2016-05-24 06:19:49 +00:00
|
|
|
@staticmethod
|
2016-05-20 21:11:42 +00:00
|
|
|
def generate_RSA(bits=2048):
|
|
|
|
'''
|
|
|
|
Generate an RSA keypair with an exponent of 65537 in PEM format
|
|
|
|
param: bits The key length in bits
|
|
|
|
Return private key and public key
|
|
|
|
'''
|
|
|
|
new_key = RSA.generate(2048, os.urandom)
|
2016-05-24 06:19:49 +00:00
|
|
|
public_key = new_key.publickey().exportKey("OpenSSH")
|
|
|
|
private_key = new_key.exportKey("PEM")
|
2016-05-20 21:11:42 +00:00
|
|
|
return private_key, public_key
|
|
|
|
|
2016-05-24 06:19:49 +00:00
|
|
|
def generate_keys(self):
|
|
|
|
private_key, public_key = self.generate_RSA()
|
|
|
|
self.public_key = public_key
|
|
|
|
self.save(update_fields=['public_key'])
|
2016-07-05 04:44:15 +00:00
|
|
|
return private_key, public_key
|
2016-05-24 06:19:49 +00:00
|
|
|
|
2016-06-10 04:50:49 +00:00
|
|
|
def cancel_plan(self):
|
|
|
|
self.status = self.CANCELED_STATUS
|
|
|
|
self.save(update_fields=['status'])
|
|
|
|
|
2016-04-26 06:16:03 +00:00
|
|
|
|
2016-07-11 03:08:51 +00:00
|
|
|
class HostingOrder(AssignPermissionsMixin, models.Model):
|
2016-05-03 05:59:40 +00:00
|
|
|
|
|
|
|
ORDER_APPROVED_STATUS = 'Approved'
|
|
|
|
ORDER_DECLINED_STATUS = 'Declined'
|
|
|
|
|
2016-05-12 06:57:34 +00:00
|
|
|
vm_plan = models.ForeignKey(VirtualMachinePlan, related_name='hosting_orders')
|
2016-04-26 06:16:03 +00:00
|
|
|
customer = models.ForeignKey(StripeCustomer)
|
|
|
|
billing_address = models.ForeignKey(BillingAddress)
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
approved = models.BooleanField(default=False)
|
2016-05-03 05:59:40 +00:00
|
|
|
last4 = models.CharField(max_length=4)
|
|
|
|
cc_brand = models.CharField(max_length=10)
|
2016-04-26 06:16:03 +00:00
|
|
|
stripe_charge_id = models.CharField(max_length=100, null=True)
|
|
|
|
|
2016-07-11 03:08:51 +00:00
|
|
|
permissions = ('view_hostingorder',)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
('view_hostingorder', 'View Hosting Order'),
|
|
|
|
)
|
|
|
|
|
2016-05-14 06:42:42 +00:00
|
|
|
def __str__(self):
|
|
|
|
return "%s" % (self.id)
|
|
|
|
|
2016-05-03 05:59:40 +00:00
|
|
|
@cached_property
|
|
|
|
def status(self):
|
|
|
|
return self.ORDER_APPROVED_STATUS if self.approved else self.ORDER_DECLINED_STATUS
|
|
|
|
|
2016-04-26 06:16:03 +00:00
|
|
|
@classmethod
|
2016-05-12 06:57:34 +00:00
|
|
|
def create(cls, vm_plan=None, customer=None, billing_address=None):
|
|
|
|
instance = cls.objects.create(vm_plan=vm_plan, customer=customer,
|
2016-04-26 06:16:03 +00:00
|
|
|
billing_address=billing_address)
|
2016-07-11 03:08:51 +00:00
|
|
|
instance.assign_permissions(customer.user)
|
2016-04-26 06:16:03 +00:00
|
|
|
return instance
|
|
|
|
|
|
|
|
def set_approved(self):
|
|
|
|
self.approved = True
|
|
|
|
self.save()
|
|
|
|
|
|
|
|
def set_stripe_charge(self, stripe_charge):
|
|
|
|
self.stripe_charge_id = stripe_charge.id
|
2016-05-03 05:59:40 +00:00
|
|
|
self.last4 = stripe_charge.source.last4
|
|
|
|
self.cc_brand = stripe_charge.source.brand
|
2016-04-26 06:16:03 +00:00
|
|
|
self.save()
|
|
|
|
|
2016-04-23 07:22:44 +00:00
|
|
|
|
2017-04-23 16:54:41 +00:00
|
|
|
class ManageVM(models.Model):
|
2017-03-15 12:02:55 +00:00
|
|
|
def has_add_permission(self, request):
|
|
|
|
return False
|
2016-04-23 07:22:44 +00:00
|
|
|
|
2017-03-15 12:02:55 +00:00
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
|
|
return False
|
2016-04-23 07:22:44 +00:00
|
|
|
|
2017-03-15 12:02:55 +00:00
|
|
|
class Meta:
|
|
|
|
managed = False
|