adding integration opennebula-hosting app

This commit is contained in:
Levi 2017-05-03 23:19:32 -05:00
parent 2658205008
commit ed806910e6
20 changed files with 641 additions and 239 deletions

View File

@ -1,10 +1,13 @@
import random
import string
from django import forms
from membership.models import CustomUser
from django.contrib.auth import authenticate
from utils.stripe_utils import StripeUtils
from .models import HostingOrder, VirtualMachinePlan
from .models import HostingOrder, VirtualMachinePlan, UserHostingKey
class HostingOrderAdminForm(forms.ModelForm):
@ -83,3 +86,40 @@ class HostingUserSignupForm(forms.ModelForm):
if not confirm_password == password:
raise forms.ValidationError("Passwords don't match")
return confirm_password
class UserHostingKeyForm(forms.ModelForm):
private_key = forms.CharField(widget=forms.PasswordInput(), required=False)
public_key = forms.CharField(widget=forms.PasswordInput(), required=False)
user = forms.models.ModelChoiceField(queryset=CustomUser.objects.all(), required=False)
name = forms.CharField(required=False)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(UserHostingKeyForm, self).__init__(*args, **kwargs)
# self.initial['user'].initial = self.request.user.id
# print(self.fields)
def clean_name(self):
return ''.join(random.choice(string.ascii_lowercase) for i in range(7))
def clean_user(self):
return self.request.user
def clean(self):
cleaned_data = self.cleaned_data
print(cleaned_data)
if not cleaned_data.get('public_key'):
private_key, public_key = UserHostingKey.generate_keys()
cleaned_data.update({
'private_key': private_key,
'public_key': public_key
})
return cleaned_data
class Meta:
model = UserHostingKey
fields = ['user', 'public_key', 'name']

View File

@ -7,51 +7,100 @@ class Command(BaseCommand):
def get_data(self):
return [
{
'base_price': 10,
'core_price': 5,
'memory_price': 2,
'disk_size_price': 0.6,
'cores': 1,
'memory': 2,
'disk_size': 10
},
{
'base_price': 10,
'core_price': 5,
'memory_price': 2,
'disk_size_price': 0.6,
'cores': 1,
'memory': 2,
'disk_size': 100
},
{
'base_price': 10,
'core_price': 5,
'memory_price': 2,
'disk_size_price': 0.6,
'cores': 2,
'memory': 4,
'disk_size': 20
},
{
'base_price': 10,
'core_price': 5,
'memory_price': 2,
'disk_size_price': 0.6,
'cores': 4,
'memory': 8,
'disk_size': 40
},
{
'base_price': 10,
'core_price': 5,
'memory_price': 2,
'disk_size_price': 0.6,
'cores': 16,
'memory': 8,
'disk_size': 40
},
]
hetzner = {
'base_price': 10,
'core_price': 10,
'memory_price': 5,
'disk_size_price': 1,
'core_price': 5,
'memory_price': 2,
'disk_size_price': 0.6,
'description': 'VM auf einzelner HW, Raid1, kein HA',
'location': 'DE'
}
return {
# 'hetzner_nug': {
# 'base_price': 5,
# 'memory_price': 2,
# 'core_price': 2,
# 'disk_size_price': 0.5,
# 'description': 'VM ohne Uptime Garantie'
# },
'hetzner': hetzner,
# 'hetzner_raid6': {
# 'base_price': hetzner['base_price']*1.2,
# 'core_price': hetzner['core_price']*1.2,
# 'memory_price': hetzner['memory_price']*1.2,
# 'disk_size_price': hetzner['disk_size_price']*1.2,
# 'description': 'VM auf einzelner HW, Raid1, kein HA'
# return {
# # 'hetzner_nug': {
# # 'base_price': 5,
# # 'memory_price': 2,
# # 'core_price': 2,
# # 'disk_size_price': 0.5,
# # 'description': 'VM ohne Uptime Garantie'
# # },
# 'hetzner': hetzner,
# # 'hetzner_raid6': {
# # 'base_price': hetzner['base_price']*1.2,
# # 'core_price': hetzner['core_price']*1.2,
# # 'memory_price': hetzner['memory_price']*1.2,
# # 'disk_size_price': hetzner['disk_size_price']*1.2,
# # 'description': 'VM auf einzelner HW, Raid1, kein HA'
# },
# 'hetzner_glusterfs': {
# 'base_price': hetzner['base_price']*1.4,
# 'core_price': hetzner['core_price']*1.4,
# 'memory_price': hetzner['memory_price']*1.4,
# 'disk_size_price': hetzner['disk_size_price']*1.4,
# 'description': 'VM auf einzelner HW, Raid1, kein HA'
# },
'bern': {
'base_price': 12,
'core_price': 25,
'memory_price': 7,
'disk_size_price': 0.70,
'description': "VM in Bern, HA Setup ohne HA Garantie",
'location': 'CH',
}
}
# # },
# # 'hetzner_glusterfs': {
# # 'base_price': hetzner['base_price']*1.4,
# # 'core_price': hetzner['core_price']*1.4,
# # 'memory_price': hetzner['memory_price']*1.4,
# # 'disk_size_price': hetzner['disk_size_price']*1.4,
# # 'description': 'VM auf einzelner HW, Raid1, kein HA'
# # },
# 'bern': {
# 'base_price': 12,
# 'core_price': 25,
# 'memory_price': 7,
# 'disk_size_price': 0.70,
# 'description': "VM in Bern, HA Setup ohne HA Garantie",
# 'location': 'CH',
# }
# }
def handle(self, *args, **options):
data = self.get_data()
[VirtualMachineType.objects.create(hosting_company=key, **data[key])
for key in data.keys()]
vm_data = self.get_data()
for vm in vm_data:
VirtualMachineType.objects.create(**vm)

View File

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-04-29 18:28
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', '0027_auto_20160711_0210'),
]
operations = [
migrations.CreateModel(
name='ManageVM',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
options={
'managed': False,
},
),
migrations.CreateModel(
name='UserHostingKey',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('public_key', models.TextField()),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-04-30 19:04
from __future__ import unicode_literals
import datetime
from django.db import migrations, models
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('hosting', '0028_managevm_userhostingkey'),
]
operations = [
migrations.AddField(
model_name='userhostingkey',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2017, 4, 30, 19, 4, 20, 780173, tzinfo=utc)),
preserve_default=False,
),
]

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-04-30 19:09
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hosting', '0029_userhostingkey_created_at'),
]
operations = [
migrations.AddField(
model_name='userhostingkey',
name='name',
field=models.CharField(default='', max_length=100),
preserve_default=False,
),
]

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-05-03 05:54
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('hosting', '0030_userhostingkey_name'),
]
operations = [
migrations.RemoveField(
model_name='virtualmachinetype',
name='hosting_company',
),
migrations.RemoveField(
model_name='virtualmachinetype',
name='location',
),
]

View File

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-05-04 03:15
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hosting', '0031_auto_20170503_0554'),
]
operations = [
migrations.AddField(
model_name='virtualmachinetype',
name='cores',
field=models.IntegerField(default=0),
preserve_default=False,
),
migrations.AddField(
model_name='virtualmachinetype',
name='disk_size',
field=models.IntegerField(default=0),
preserve_default=False,
),
migrations.AddField(
model_name='virtualmachinetype',
name='memory',
field=models.IntegerField(default=0),
preserve_default=False,
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-05-04 03:23
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hosting', '0032_auto_20170504_0315'),
]
operations = [
migrations.AddField(
model_name='virtualmachinetype',
name='configuration',
field=models.CharField(choices=[('debian', 'Debian 8'), ('ubuntu', 'Ubuntu 16.06'), ('devuan', 'Devuan 1'), ('centos', 'CentOS 7')], default='ubuntu', max_length=10),
),
]

View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-05-04 03:31
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('hosting', '0033_virtualmachinetype_configuration'),
]
operations = [
migrations.RemoveField(
model_name='virtualmachinetype',
name='configuration',
),
migrations.AlterField(
model_name='virtualmachineplan',
name='configuration',
field=models.CharField(choices=[('debian', 'Debian 8'), ('ubuntu', 'Ubuntu 16.06'), ('devuan', 'Devuan 1'), ('centos', 'CentOS 7')], max_length=20),
),
migrations.AlterField(
model_name='virtualmachineplan',
name='vm_type',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='hosting.VirtualMachineType'),
),
]

View File

@ -1,23 +1,32 @@
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
from .models import VirtualMachinePlan
from .models import VirtualMachinePlan, VirtualMachineType
class ProcessVMSelectionMixin(object):
def post(self, request, *args, **kwargs):
hosting = request.POST.get('configuration')
configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(hosting)
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')
}
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
})
# 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

View File

@ -7,7 +7,7 @@ from django.utils.functional import cached_property
from Crypto.PublicKey import RSA
from stored_messages.settings import stored_messages_settings
from membership.models import StripeCustomer
from membership.models import StripeCustomer, CustomUser
from utils.models import BillingAddress
from utils.mixins import AssignPermissionsMixin
from .managers import VMPlansManager
@ -15,88 +15,71 @@ from .managers import VMPlansManager
class VirtualMachineType(models.Model):
BASE_PRICE = 0.5
HETZNER_NUG = 'hetzner_nug'
HETZNER = 'hetzner'
HETZNER_R6 = 'hetzner_raid6'
HETZNER_G = 'hetzner_glusterfs'
BERN = 'bern'
DE_LOCATION = 'DE'
CH_LOCATION = 'CH'
HOSTING_TYPES = (
(HETZNER_NUG, 'Hetzner No Uptime Guarantee'),
(HETZNER, 'Hetzner'),
(HETZNER_R6, 'Hetzner Raid6'),
(HETZNER_G, 'Hetzner Glusterfs'),
(BERN, 'Bern'),
)
LOCATIONS_CHOICES = (
(DE_LOCATION, 'Germany'),
(CH_LOCATION, 'Switzerland'),
)
description = models.TextField()
base_price = models.FloatField()
memory_price = models.FloatField()
core_price = models.FloatField()
disk_size_price = models.FloatField()
hosting_company = models.CharField(max_length=30, choices=HOSTING_TYPES)
location = models.CharField(max_length=3, choices=LOCATIONS_CHOICES)
cores = models.IntegerField()
memory = models.IntegerField()
disk_size = models.IntegerField()
def __str__(self):
return "%s" % (self.get_hosting_company_display())
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, 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
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
# @classmethod
# def get_price(cls, vm_template):
# return cls.BASE_PRICE * vm_template
@classmethod
def get_specs(cls, vm_template):
def get_specs(self):
return {
'memory': 1024 * vm_template,
'cores': 0.1 * vm_template,
'disk_size': 10000 * vm_template
'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 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 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,
'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,
'default_price': self.defeault_price(),
'location_code': self.location,
'location': self.get_location_display(),
'id': self.id,
'final_price': self.final_price,
'cores': self.cores,
'memory': self.memory,
'disk_size': self.disk_size
}
@ -112,14 +95,21 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model):
(CANCELED_STATUS, 'Canceled')
)
DJANGO = 'django'
RAILS = 'rails'
NODEJS = 'nodejs'
# DJANGO = 'django'
# RAILS = 'rails'
# NODEJS = 'nodejs'
# VM_CONFIGURATION = (
# (DJANGO, 'Ubuntu 14.04, Django'),
# (RAILS, 'Ubuntu 14.04, Rails'),
# (NODEJS, 'Debian, NodeJS'),
# )
VM_CONFIGURATION = (
(DJANGO, 'Ubuntu 14.04, Django'),
(RAILS, 'Ubuntu 14.04, Rails'),
(NODEJS, 'Debian, NodeJS'),
('debian', 'Debian 8'),
('ubuntu', 'Ubuntu 16.06'),
('devuan', 'Devuan 1'),
('centos', 'CentOS 7')
)
permissions = ('view_virtualmachineplan',
@ -129,7 +119,7 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model):
cores = models.IntegerField()
memory = models.IntegerField()
disk_size = models.IntegerField()
vm_type = models.ForeignKey(VirtualMachineType)
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)
@ -147,13 +137,13 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model):
def __str__(self):
return self.name
@cached_property
def hosting_company_name(self):
return self.vm_type.get_hosting_company_display()
# @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 location(self):
# return self.vm_type.get_location_display()
@cached_property
def name(self):
@ -173,24 +163,6 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model):
instance.assign_permissions(user)
return instance
@staticmethod
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)
public_key = new_key.publickey().exportKey("OpenSSH")
private_key = new_key.exportKey("PEM")
return private_key, public_key
def generate_keys(self):
private_key, public_key = self.generate_RSA()
self.public_key = public_key
self.save(update_fields=['public_key'])
return private_key, public_key
def cancel_plan(self):
self.status = self.CANCELED_STATUS
self.save(update_fields=['status'])
@ -242,6 +214,32 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
self.save()
class UserHostingKey(models.Model):
user = models.ForeignKey(CustomUser)
public_key = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=100)
@staticmethod
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)
public_key = new_key.publickey().exportKey("OpenSSH")
private_key = new_key.exportKey("PEM")
return private_key, public_key
@classmethod
def generate_keys(cls):
private_key, public_key = cls.generate_RSA()
# self.public_key = public_key
# self.save(update_fields=['public_key'])
return private_key, public_key
class ManageVM(models.Model):
def has_add_permission(self, request):
return False

View File

@ -72,6 +72,11 @@
<i class="fa fa-credit-card"></i> {% trans "My Orders"%}
</a>
</li>
<li>
<a href="{% url 'hosting:key_pair' %}">
<i class="fa fa-key" aria-hidden="true"></i> {% trans "Keys"%}
</a>
</li>
<li>
<a href="{% url 'hosting:notifications' %}">
<i class="fa fa-bell"></i> {% trans "Notifications "%}

View File

@ -0,0 +1,45 @@
{% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 i18n %}
{% block content %}
<div>
<div class="container dashboard-container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h3><i class="fa fa-server" aria-hidden="true"></i> {% trans "New Virtual Machine"%} </h3>
<hr/>
<form method="POST" action="">
{% csrf_token %}
<div class="form-group">
Select VM Type:
<select name="vm_template">
{% for vm in vm_types %}
<option value="{{vm.id}}">CORE: {{vm.cores}}- RAM: {{vm.memory}} - SSD: {{vm.disk_size}} </option>
{% endfor %}
</select>
</div>
<div class="form-group">
Select VM Configuration:
<select name="configuration">
{% for config in configuration_options %}
<option value="{{config.0}}">{{config.1}} </option>
{% endfor %}
</select>
</div>
<div class="form-group">
<button class="btn btn-success" >{% trans "Start VM"%} </button>
</div>
</form>
</div>
</div>
</div>
</div>
{%endblock%}

View File

@ -24,59 +24,17 @@
{% csrf_token %}
<input type="hidden" name="hosting_company" value="{{vm.hosting_company}}">
<input type="hidden" name="location_code" value="{{vm.location_code}}">
<input type="hidden" name="vm_template" value="1">
<input type="hidden" name="vm_template" value="{{vm.id}}">
<ul class="pricing {% cycle 'p-red' 'p-black' 'p-red' 'p-yel' %}">
<li class="type">
<!-- <img src="http://bread.pp.ua/n/settings_g.svg" alt=""> -->
<h3 >{{vm.location_code}}</h3>
<br/>
<img class="img-responsive" src="{{ STATIC_URL }}hosting/img/{{vm.location_code}}_flag.png" alt="">
</li>
<li>
<!-- Single button -->
<div class="btn-group">
<div class="form-group">
<label for="cores">Location: </label>
{{vm.location}}
</div>
</div>
</li>
<li>
<label for="configuration">Configuration: </label>
{% if select_configuration %}
<select class="form-control" name="configuration" id="{{vm.hosting_company}}-configuration" data-vm-type="{{vm.hosting_company}}">
{% for key,value in configuration_options.items %}
<option value="{{key}}">{{ value }}</option>
{% endfor %}
</select>
{% else %}
<input type="hidden" name="configuration_detail" value="{{configuration_detail}}">
<input type="hidden" name="configuration" value="{{hosting}}">
<!-- Single button -->
<div class="btn-group">
<div class="form-group">
<label>Configuration: </label>
{{configuration_detail}}
</div>
</div>
{% endif %}
</li>
<li>
<!-- Single button -->
<div class="btn-group">
<div class="form-group">
<label for="cores">Cores: </label>
<select class="form-control cores-selector" name="cores" id="{{vm.hosting_company}}-cores" data-vm-type="{{vm.hosting_company}}">
{% with ''|center:10 as range %}
{% for _ in range %}
<option>{{ forloop.counter }}</option>
{% endfor %}
{% endwith %}
</select>
<label for="cores">Cores: {{vm.cores}}</label>
</div>
</div>
@ -84,30 +42,28 @@
<li>
<div class="form-group">
<div class="btn-group">
<label for="memory">Memory: </label>
<select class="form-control memory-selector" name="memory" id="{{vm.hosting_company}}-memory" data-vm-type="{{vm.hosting_company}}">
{% with ''|center:50 as range %}
{% for _ in range %}
<option>{{ forloop.counter }}</option>
{% endfor %}
{% endwith %}
</select>
<span>GiB</span>
<label for="memory">Memory: {{vm.memory}} GiB</label>
</div>
</div>
</li>
<li>
<div class="form-group row">
<div class="col-xs-offset-1 col-xs-9 col-sm-12 col-md-12 col-md-offset-0">
<label for="Disk Size">Disk Size: </label>
<input class="form-control short-input text-center disk-space-selector" name="disk_space" type="number" id="{{vm.hosting_company}}-disk_space" min="10" value="10" step="10" data-vm-type="{{vm.hosting_company}}"/>
<span>GiB</span>
<label for="Disk Size">Disk Size: {{vm.disk_size}} GiB</label>
</div>
</div>
</li>
<li>
<input id="{{vm.hosting_company}}-final-price-input" type="hidden" name="final_price" value="{{vm.default_price|floatformat}}">
<h3 id="{{vm.hosting_company}}-final-price">{{vm.default_price|floatformat}}CHF</h3>
<label for="configuration">Configuration: </label>
<select class="form-control" name="configuration" id="{{vm.hosting_company}}-configuration" data-vm-type="{{vm.hosting_company}}">
{% for key,value in configuration_options.items %}
<option value="{{key}}">{{ value }}</option>
{% endfor %}
</select>
</li>
<li>
<input type="hidden" name="final_price" value="{{vm.final_price|floatformat}}">
<h3 id="{{vm.hosting_company}}-final-price">{{vm.final_price|floatformat}}CHF</h3>
<span>per month</span>
</li>
<li>

View File

@ -65,7 +65,7 @@
{% url 'hosting:payment' as payment_url %}
{% if payment_url in request.META.HTTP_REFERER %}
<div class=" content pull-right">
<a href="{% url 'hosting:virtual_machine_key' order.vm_plan.id %}" ><button class="btn btn-info">{% trans "Finish Configuration"%}</button></a>
<a href="{% url 'hosting:key_pair'%}" ><button class="btn btn-info">{% trans "Finish Configuration"%}</button></a>
</div>
{% endif %}
</div>

View File

@ -86,11 +86,11 @@
<h3><b>Billing Amount</b></h3>
<hr>
<div class="content">
<p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.location_code}}</span></p>
<hr>
<!-- <p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.location_code}}</span></p> -->
<!-- <hr> -->
<p><b>Cores</b> <span class="pull-right">{{request.session.vm_specs.cores}}</span></p>
<hr>
<p><b>Configuration</b> <span class="pull-right">{{request.session.vm_specs.configuration_detail}}</span></p>
<p><b>Configuration</b> <span class="pull-right">{{request.session.vm_specs.configuration_display}}</span></p>
<hr>
<p><b>Memory</b> <span class="pull-right">{{request.session.vm_specs.memory}} GiB</span></p>
<hr>

View File

@ -6,30 +6,75 @@
<div class="row">
<div class="col-md-9 col-md-offset-2">
<div class="col-sm-12">
<h3><i class="fa fa-key" aria-hidden="true"></i>{% trans "SSH Private Key"%} </h3>
<form method="POST" action="" >
{% csrf_token %}
<h3><i class="fa fa-key" aria-hidden="true"></i>{% trans "Access Key"%} </h3>
<hr/>
{% if not user_key %}
<div class="alert alert-warning">
{% trans "Upload your own key. "%}
</div>
<div class="form-group">
<label for="comment">Paste here your public key</label>
<textarea class="form-control" rows="6" name="public_key"></textarea>
</div>
<div class="form-group">
<button class="btn btn-success">{% trans "Upload Key"%} </a>
</div>
<div class="alert alert-warning">
{% trans "Or generate a new key pair."%}
</div>
<div class="form-group">
<button class="btn btn-success">{% trans "Generate Key Pair"%} </a>
</div>
{% else %}
<h5> Use your created key to access to the machine. If you lost it, contact us. </h5>
<table class="table borderless table-hover">
<br/>
<thead>
<tr>
<th>{% trans "Name"%}</th>
<th>{% trans "Created at"%} </th>
<th>{% trans "Status"%} </th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">{{user_key.name}}</td>
<td>{{user_key.created_at}}</td>
<td>
<span class="h3 label label-success"><strong>Active</strong></span>
</td>
</tr>
</tbody>
</table>
{% endif %}
</form>
{% if private_key %}
<div class="alert alert-warning">
<strong>{% trans "Warning!"%}</strong>{% trans "You can view your SSH private key once. Copy it or if it wasn't downloaded automatically, just click on Download to start it."%}
</div>
<div class="form-group">
<label for="comment">private_key.pem</label>
<textarea class="form-control" rows="6" id="ssh_key">{{private_key}}</textarea>
<textarea class="form-control" rows="6" id="ssh_key" type="hidden" style="display:none">{{private_key}}</textarea>
</div>
<div class="form-group pull-right">
<!-- <div class="form-group pull-right">
<button type="button" id="copy_to_clipboard" data-clipboard-target="#ssh_key" class="btn btn-warning"
data-toggle="tooltip" data-placement="bottom" title="Copied" data-trigger="click">{% trans "Copy to Clipboard"%}</button>
<button type="button" id="download_ssh_key" class="btn btn-warning">{% trans "Download"%}</button>
</div>
</div> -->
{% else %}
<div class="alert alert-warning">
<!-- <div class="alert alert-warning">
<strong>{% trans "Warning!"%}</strong>{% trans "Your SSH private key was already generated and downloaded, if you lost it, contact us. "%}
</div>
{% endif %}
<a class="btn btn-success" href="{% url 'hosting:virtual_machines' virtual_machine.id %}">{% trans "Go to my Virtual Machine Dashboard"%} </a>
--> {% endif %}
<!-- <a class="btn btn-success" href="{% url 'hosting:virtual_machines' %}">{% trans "Generate my key"%} </a> -->
<div class="clearfix"></div>
</div>
</div>
@ -42,11 +87,12 @@
<!-- Force to download ssh key on page load -->
<script type="text/javascript">
var key = window.document.getElementById('ssh_key');
var key = window.document.getElementById('ssh_key');
var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob(['key'], {type: 'text'}));
a.download = 'private_key.pem';
a.href = window.URL.createObjectURL(new Blob([key.value], {type: 'text'}));
a.download = '{{key_name}}.pem';
// Append anchor to body.
document.body.appendChild(a);

View File

@ -6,7 +6,10 @@
<div class="row">
<div class="col-md-8 col-md-offset-2">
<table class="table borderless table-hover">
<h3><i class="fa fa-server" aria-hidden="true"></i>{% trans "Virtual Machines"%} </h3>
<h3 class="pull-left"><i class="fa fa-server" aria-hidden="true"></i> {% trans "Virtual Machines"%} </h3>
<p class="pull-right">
<a class="btn btn-success" href="{% url 'hosting:create-virtual-machine' %}" >{% trans "Create VM"%} </a>
</p>
<br/>
<thead>
<tr>

View File

@ -4,7 +4,8 @@ from .views import DjangoHostingView, RailsHostingView, PaymentVMView,\
NodeJSHostingView, LoginView, SignupView, IndexView, \
OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\
VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \
MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView
MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView,\
CreateVirtualMachinesView
urlpatterns = [
url(r'index/?$', IndexView.as_view(), name='index'),
@ -16,13 +17,14 @@ urlpatterns = [
url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'),
url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'),
url(r'cancel_order/(?P<pk>\d+)/?$', OrdersHostingDeleteView.as_view(), name='delete_order'),
url(r'create-virtual-machine/?$', CreateVirtualMachinesView.as_view(), name='create-virtual-machine'),
url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'),
url(r'my-virtual-machines/(?P<pk>\d+)/?$', VirtualMachineView.as_view(),
name='virtual_machines'),
# url(r'my-virtual-machines/(?P<pk>\d+)/delete/?$', VirtualMachineCancelView.as_view(),
# name='virtual_machines_cancel'),
url(r'my-virtual-machines/(?P<pk>\d+)/key/?$', GenerateVMSSHKeysView.as_view(),
name='virtual_machine_key'),
url(r'vm-key-pair/?$', GenerateVMSSHKeysView.as_view(),
name='key_pair'),
url(r'^notifications/$', NotificationsView.as_view(), name='notifications'),
url(r'^notifications/(?P<pk>\d+)/?$', MarkAsReadNotificationView.as_view(),
name='read_notification'),

View File

@ -8,6 +8,8 @@ from django.views.generic import View, CreateView, FormView, ListView, DetailVie
from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login
from django.conf import settings
from django.shortcuts import redirect
from guardian.mixins import PermissionRequiredMixin
from stored_messages.settings import stored_messages_settings
@ -15,13 +17,14 @@ 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
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
from utils.mailer import BaseEmail
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder
from .forms import HostingUserSignupForm, HostingUserLoginForm
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, UserHostingKey
from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyForm
from .mixins import ProcessVMSelectionMixin
from .opennebula_functions import HostingManageVMAdmin
@ -40,6 +43,7 @@ class DjangoHostingView(ProcessVMSelectionMixin, View):
'google_analytics': "UA-62285904-6",
'email': "info@django-hosting.ch",
'vm_types': VirtualMachineType.get_serialized_vm_types(),
'configuration_options': dict(VirtualMachinePlan.VM_CONFIGURATION)
}
return context
@ -208,26 +212,52 @@ class MarkAsReadNotificationView(LoginRequiredMixin, UpdateView):
return HttpResponseRedirect(reverse('hosting:notifications'))
class GenerateVMSSHKeysView(LoginRequiredMixin, DetailView):
model = VirtualMachinePlan
class GenerateVMSSHKeysView(LoginRequiredMixin, FormView):
form_class = UserHostingKeyForm
model = UserHostingKey
template_name = 'hosting/virtual_machine_key.html'
success_url = reverse_lazy('hosting:orders')
login_url = reverse_lazy('hosting:login')
context_object_name = "virtual_machine"
def get_context_data(self, **kwargs):
try:
user_key = UserHostingKey.objects.get(
user=self.request.user
)
except UserHostingKey.DoesNotExist:
user_key = None
context = super(
GenerateVMSSHKeysView,
self
).get_context_data(**kwargs)
context.update({
'user_key': user_key
})
context = super(GenerateVMSSHKeysView, self).get_context_data(**kwargs)
vm = self.get_object()
if not vm.public_key:
private_key, public_key = vm.generate_keys()
context.update({
'private_key': private_key,
'public_key': public_key
})
return context
return context
def get_form_kwargs(self):
kwargs = super(GenerateVMSSHKeysView, self).get_form_kwargs()
kwargs.update({'request': self.request})
return kwargs
def form_valid(self, form):
form.save()
context = self.get_context_data()
if form.cleaned_data.get('private_key'):
context.update({
'private_key': form.cleaned_data.get('private_key'),
'key_name': form.cleaned_data.get('name')
})
# print("form", form.cleaned_data)
return render(self.request, self.template_name, context)
class PaymentVMView(LoginRequiredMixin, FormView):
template_name = 'hosting/payment.html'
@ -251,11 +281,11 @@ class PaymentVMView(LoginRequiredMixin, FormView):
vm_template = specifications.get('vm_template', 1)
vm_type = VirtualMachineType.objects.first()
vm_type = VirtualMachineType.objects.get(id=vm_template)
final_price = VirtualMachineType.get_price(vm_template)
specs = vm_type.get_specs()
specs = VirtualMachineType.get_specs(vm_template)
final_price = vm_type.calculate_price()
plan_data = {
'vm_type': vm_type,
@ -318,9 +348,9 @@ class PaymentVMView(LoginRequiredMixin, FormView):
# 'vm_template': vm_template
# }
hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin)
hosting_admin.init_opennebula_client(request)
hosting_admin.create(request)
# hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin)
# hosting_admin.init_opennebula_client(request)
# hosting_admin.create(request)
# Send notification to ungleich as soon as VM has been booked
context = {
@ -381,13 +411,47 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView):
ordering = '-id'
def get_queryset(self):
hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin)
print(hosting_admin.show_vms(self.request))
# 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 CreateVirtualMachinesView(LoginRequiredMixin, View):
template_name = "hosting/create_virtual_machine.html"
login_url = reverse_lazy('hosting:login')
def get(self, request, *args, **kwargs):
context = {
'vm_types': VirtualMachineType.get_serialized_vm_types(),
'configuration_options': VirtualMachinePlan.VM_CONFIGURATION
}
# 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
})
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, UpdateView):
template_name = "hosting/virtual_machine_detail.html"
login_url = reverse_lazy('hosting:login')