Merge pull request #217 from levivm/opennebula-integration
Opennebula integration
This commit is contained in:
		
				commit
				
					
						e1a61ba930
					
				
			
		
					 23 changed files with 756 additions and 226 deletions
				
			
		|  | @ -1,10 +1,13 @@ | ||||||
|  | import random | ||||||
|  | import string | ||||||
| from django import forms | from django import forms | ||||||
| from membership.models import CustomUser | from membership.models import CustomUser | ||||||
| from django.contrib.auth import authenticate | from django.contrib.auth import authenticate | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| from utils.stripe_utils import StripeUtils | from utils.stripe_utils import StripeUtils | ||||||
| 
 | 
 | ||||||
| from .models import HostingOrder, VirtualMachinePlan | from .models import HostingOrder, VirtualMachinePlan, UserHostingKey | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class HostingOrderAdminForm(forms.ModelForm): | class HostingOrderAdminForm(forms.ModelForm): | ||||||
|  | @ -83,3 +86,40 @@ class HostingUserSignupForm(forms.ModelForm): | ||||||
|         if not confirm_password == password: |         if not confirm_password == password: | ||||||
|             raise forms.ValidationError("Passwords don't match") |             raise forms.ValidationError("Passwords don't match") | ||||||
|         return confirm_password |         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'] | ||||||
|  |  | ||||||
|  | @ -7,51 +7,100 @@ class Command(BaseCommand): | ||||||
| 
 | 
 | ||||||
|     def get_data(self): |     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 = { |         hetzner = { | ||||||
|             'base_price': 10, |             'base_price': 10, | ||||||
|             'core_price': 10, |             'core_price': 5, | ||||||
|             'memory_price': 5, |             'memory_price': 2, | ||||||
|             'disk_size_price': 1, |             'disk_size_price': 0.6, | ||||||
|             'description': 'VM auf einzelner HW, Raid1, kein HA', |             'description': 'VM auf einzelner HW, Raid1, kein HA', | ||||||
|             'location': 'DE' |             'location': 'DE' | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return { |         # return { | ||||||
|             # 'hetzner_nug': { |         #     # 'hetzner_nug': { | ||||||
|             #     'base_price': 5, |         #     #     'base_price': 5, | ||||||
|             #     'memory_price': 2, |         #     #     'memory_price': 2, | ||||||
|             #     'core_price': 2, |         #     #     'core_price': 2, | ||||||
|             #     'disk_size_price': 0.5, |         #     #     'disk_size_price': 0.5, | ||||||
|             #     'description': 'VM ohne Uptime Garantie' |         #     #     'description': 'VM ohne Uptime Garantie' | ||||||
|             # }, |         #     # }, | ||||||
|             'hetzner': hetzner, |         #     'hetzner': hetzner, | ||||||
|             # 'hetzner_raid6': { |         #     # 'hetzner_raid6': { | ||||||
|             #     'base_price': hetzner['base_price']*1.2, |         #     #     'base_price': hetzner['base_price']*1.2, | ||||||
|             #     'core_price': hetzner['core_price']*1.2, |         #     #     'core_price': hetzner['core_price']*1.2, | ||||||
|             #     'memory_price': hetzner['memory_price']*1.2, |         #     #     'memory_price': hetzner['memory_price']*1.2, | ||||||
|             #     'disk_size_price': hetzner['disk_size_price']*1.2, |         #     #     'disk_size_price': hetzner['disk_size_price']*1.2, | ||||||
|             #     'description': 'VM auf einzelner HW, Raid1, kein HA' |         #     #     'description': 'VM auf einzelner HW, Raid1, kein HA' | ||||||
| 
 | 
 | ||||||
|             # }, |         #     # }, | ||||||
|             # 'hetzner_glusterfs': { |         #     # 'hetzner_glusterfs': { | ||||||
|             #     'base_price': hetzner['base_price']*1.4, |         #     #     'base_price': hetzner['base_price']*1.4, | ||||||
|             #     'core_price': hetzner['core_price']*1.4, |         #     #     'core_price': hetzner['core_price']*1.4, | ||||||
|             #     'memory_price': hetzner['memory_price']*1.4, |         #     #     'memory_price': hetzner['memory_price']*1.4, | ||||||
|             #     'disk_size_price': hetzner['disk_size_price']*1.4, |         #     #     'disk_size_price': hetzner['disk_size_price']*1.4, | ||||||
|             #     'description': 'VM auf einzelner HW, Raid1, kein HA' |         #     #     'description': 'VM auf einzelner HW, Raid1, kein HA' | ||||||
|             # }, |         #     # }, | ||||||
|             'bern': { |         #     'bern': { | ||||||
|                 'base_price': 12, |         #         'base_price': 12, | ||||||
|                 'core_price': 25, |         #         'core_price': 25, | ||||||
|                 'memory_price': 7, |         #         'memory_price': 7, | ||||||
|                 'disk_size_price': 0.70, |         #         'disk_size_price': 0.70, | ||||||
|                 'description': "VM in Bern, HA Setup ohne HA Garantie", |         #         'description': "VM in Bern, HA Setup ohne HA Garantie", | ||||||
|                 'location': 'CH', |         #         'location': 'CH', | ||||||
|             } |         #     } | ||||||
|         } |         # } | ||||||
| 
 | 
 | ||||||
|     def handle(self, *args, **options): |     def handle(self, *args, **options): | ||||||
| 
 | 
 | ||||||
|         data = self.get_data() |         vm_data = self.get_data() | ||||||
|         [VirtualMachineType.objects.create(hosting_company=key, **data[key]) |         for vm in vm_data: | ||||||
|             for key in data.keys()] |             VirtualMachineType.objects.create(**vm) | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								hosting/migrations/0028_managevm_userhostingkey.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								hosting/migrations/0028_managevm_userhostingkey.py
									
										
									
									
									
										Normal 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)), | ||||||
|  |             ], | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										23
									
								
								hosting/migrations/0029_userhostingkey_created_at.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								hosting/migrations/0029_userhostingkey_created_at.py
									
										
									
									
									
										Normal 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, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										21
									
								
								hosting/migrations/0030_userhostingkey_name.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								hosting/migrations/0030_userhostingkey_name.py
									
										
									
									
									
										Normal 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, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										23
									
								
								hosting/migrations/0031_auto_20170503_0554.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								hosting/migrations/0031_auto_20170503_0554.py
									
										
									
									
									
										Normal 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', | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										33
									
								
								hosting/migrations/0032_auto_20170504_0315.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								hosting/migrations/0032_auto_20170504_0315.py
									
										
									
									
									
										Normal 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, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										20
									
								
								hosting/migrations/0033_virtualmachinetype_configuration.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								hosting/migrations/0033_virtualmachinetype_configuration.py
									
										
									
									
									
										Normal 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), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										30
									
								
								hosting/migrations/0034_auto_20170504_0331.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								hosting/migrations/0034_auto_20170504_0331.py
									
										
									
									
									
										Normal 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'), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										21
									
								
								hosting/migrations/0035_virtualmachineplan_opennebula_id.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								hosting/migrations/0035_virtualmachineplan_opennebula_id.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # Generated by Django 1.9.4 on 2017-05-06 23:02 | ||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('hosting', '0034_auto_20170504_0331'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='virtualmachineplan', | ||||||
|  |             name='opennebula_id', | ||||||
|  |             field=models.IntegerField(default=0), | ||||||
|  |             preserve_default=False, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										20
									
								
								hosting/migrations/0036_auto_20170506_2312.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								hosting/migrations/0036_auto_20170506_2312.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # Generated by Django 1.9.4 on 2017-05-06 23:12 | ||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('hosting', '0035_virtualmachineplan_opennebula_id'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='virtualmachineplan', | ||||||
|  |             name='opennebula_id', | ||||||
|  |             field=models.IntegerField(null=True), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -1,23 +1,32 @@ | ||||||
| from django.shortcuts import redirect | from django.shortcuts import redirect | ||||||
| from django.core.urlresolvers import reverse | from django.core.urlresolvers import reverse | ||||||
| from .models import VirtualMachinePlan | from .models import VirtualMachinePlan, VirtualMachineType | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ProcessVMSelectionMixin(object): | class ProcessVMSelectionMixin(object): | ||||||
| 
 | 
 | ||||||
|     def post(self, request, *args, **kwargs): |     def post(self, request, *args, **kwargs): | ||||||
|         hosting = request.POST.get('configuration') |         configuration = request.POST.get('configuration') | ||||||
|         configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(hosting) |         configuration_display = dict(VirtualMachinePlan.VM_CONFIGURATION).get(configuration) | ||||||
|         vm_specs = { |         vm_template = request.POST.get('vm_template') | ||||||
|             'cores': request.POST.get('cores'), |         vm_type = VirtualMachineType.objects.get(id=vm_template) | ||||||
|             'memory': request.POST.get('memory'), |         vm_specs = vm_type.get_specs() | ||||||
|             'disk_size': request.POST.get('disk_space'), |         vm_specs.update({ | ||||||
|             'hosting_company': request.POST.get('hosting_company'), |             'configuration_display': configuration_display, | ||||||
|             'location_code': request.POST.get('location_code'), |             'configuration': configuration, | ||||||
|             'configuration': hosting, |             'final_price': vm_type.final_price, | ||||||
|             'configuration_detail': configuration_detail, |             'vm_template': vm_template | ||||||
|             'final_price': request.POST.get('final_price') |         }) | ||||||
|         } |         # 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 |         request.session['vm_specs'] = vm_specs | ||||||
|         if not request.user.is_authenticated(): |         if not request.user.is_authenticated(): | ||||||
|             request.session['vm_specs'] = vm_specs |             request.session['vm_specs'] = vm_specs | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ from django.utils.functional import cached_property | ||||||
| from Crypto.PublicKey import RSA | from Crypto.PublicKey import RSA | ||||||
| from stored_messages.settings import stored_messages_settings | 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.models import BillingAddress | ||||||
| from utils.mixins import AssignPermissionsMixin | from utils.mixins import AssignPermissionsMixin | ||||||
| from .managers import VMPlansManager | from .managers import VMPlansManager | ||||||
|  | @ -15,70 +15,71 @@ from .managers import VMPlansManager | ||||||
| 
 | 
 | ||||||
| class VirtualMachineType(models.Model): | class VirtualMachineType(models.Model): | ||||||
| 
 | 
 | ||||||
|     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() |     description = models.TextField() | ||||||
|     base_price = models.FloatField() |     base_price = models.FloatField() | ||||||
|     memory_price = models.FloatField() |     memory_price = models.FloatField() | ||||||
|     core_price = models.FloatField() |     core_price = models.FloatField() | ||||||
|     disk_size_price = models.FloatField() |     disk_size_price = models.FloatField() | ||||||
|     hosting_company = models.CharField(max_length=30, choices=HOSTING_TYPES) |     cores = models.IntegerField() | ||||||
|     location = models.CharField(max_length=3, choices=LOCATIONS_CHOICES) |     memory = models.IntegerField() | ||||||
|  |     disk_size = models.IntegerField() | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     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 |     @classmethod | ||||||
|     def get_serialized_vm_types(cls): |     def get_serialized_vm_types(cls): | ||||||
|         return [vm.get_serialized_data() |         return [vm.get_serialized_data() | ||||||
|                 for vm in cls.objects.all()] |                 for vm in cls.objects.all()] | ||||||
| 
 | 
 | ||||||
|     def calculate_price(self, specifications): |     def calculate_price(self): | ||||||
|         price = float(specifications['cores']) * self.core_price |         price = self.cores * self.core_price | ||||||
|         price += float(specifications['memory']) * self.memory_price |         price += self.memory * self.memory_price | ||||||
|         price += float(specifications['disk_size']) * self.disk_size_price |         price += self.disk_size * self.disk_size_price | ||||||
|         price += self.base_price |         # price += self.base_price | ||||||
|         return price |         return price | ||||||
| 
 | 
 | ||||||
|     def defeault_price(self): |     # @classmethod | ||||||
|         price = self.base_price |     # def get_price(cls, vm_template): | ||||||
|         price += self.core_price |     #     return cls.BASE_PRICE * vm_template | ||||||
|         price += self.memory_price | 
 | ||||||
|         price += self.disk_size_price * 10 |     def get_specs(self): | ||||||
|         return price |         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): |     def get_serialized_data(self): | ||||||
|         return { |         return { | ||||||
|             'description': self.description, |             'description': self.description, | ||||||
|             'base_price': self.base_price, |  | ||||||
|             'core_price': self.core_price, |             'core_price': self.core_price, | ||||||
|             'disk_size_price': self.disk_size_price, |             'disk_size_price': self.disk_size_price, | ||||||
|             'memory_price': self.memory_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, |             'id': self.id, | ||||||
|  |             'final_price': self.final_price, | ||||||
|  |             'cores': self.cores, | ||||||
|  |             'memory': self.memory, | ||||||
|  |             'disk_size': self.disk_size | ||||||
|  | 
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -94,14 +95,21 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): | ||||||
|         (CANCELED_STATUS, 'Canceled') |         (CANCELED_STATUS, 'Canceled') | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     DJANGO = 'django' |     # DJANGO = 'django' | ||||||
|     RAILS = 'rails' |     # RAILS = 'rails' | ||||||
|     NODEJS = 'nodejs' |     # NODEJS = 'nodejs' | ||||||
|  | 
 | ||||||
|  |     # VM_CONFIGURATION = ( | ||||||
|  |     #     (DJANGO, 'Ubuntu 14.04, Django'), | ||||||
|  |     #     (RAILS, 'Ubuntu 14.04, Rails'), | ||||||
|  |     #     (NODEJS, 'Debian, NodeJS'), | ||||||
|  |     # ) | ||||||
| 
 | 
 | ||||||
|     VM_CONFIGURATION = ( |     VM_CONFIGURATION = ( | ||||||
|         (DJANGO, 'Ubuntu 14.04, Django'), |         ('debian', 'Debian 8'), | ||||||
|         (RAILS, 'Ubuntu 14.04, Rails'), |         ('ubuntu', 'Ubuntu 16.06'), | ||||||
|         (NODEJS, 'Debian, NodeJS'), |         ('devuan', 'Devuan 1'), | ||||||
|  |         ('centos', 'CentOS 7') | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     permissions = ('view_virtualmachineplan', |     permissions = ('view_virtualmachineplan', | ||||||
|  | @ -111,12 +119,13 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): | ||||||
|     cores = models.IntegerField() |     cores = models.IntegerField() | ||||||
|     memory = models.IntegerField() |     memory = models.IntegerField() | ||||||
|     disk_size = models.IntegerField() |     disk_size = models.IntegerField() | ||||||
|     vm_type = models.ForeignKey(VirtualMachineType) |     vm_type = models.ForeignKey(VirtualMachineType, null=True) | ||||||
|     price = models.FloatField() |     price = models.FloatField() | ||||||
|     public_key = models.TextField(blank=True) |     public_key = models.TextField(blank=True) | ||||||
|     status = models.CharField(max_length=20, choices=VM_STATUS_CHOICES, default=PENDING_STATUS) |     status = models.CharField(max_length=20, choices=VM_STATUS_CHOICES, default=PENDING_STATUS) | ||||||
|     ip = models.CharField(max_length=50, blank=True) |     ip = models.CharField(max_length=50, blank=True) | ||||||
|     configuration = models.CharField(max_length=20, choices=VM_CONFIGURATION) |     configuration = models.CharField(max_length=20, choices=VM_CONFIGURATION) | ||||||
|  |     opennebula_id = models.IntegerField(null=True) | ||||||
| 
 | 
 | ||||||
|     objects = VMPlansManager() |     objects = VMPlansManager() | ||||||
| 
 | 
 | ||||||
|  | @ -129,13 +138,13 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return self.name |         return self.name | ||||||
| 
 | 
 | ||||||
|     @cached_property |     # @cached_property | ||||||
|     def hosting_company_name(self): |     # def hosting_company_name(self): | ||||||
|         return self.vm_type.get_hosting_company_display() |     #     return self.vm_type.get_hosting_company_display() | ||||||
| 
 | 
 | ||||||
|     @cached_property |     # @cached_property | ||||||
|     def location(self): |     # def location(self): | ||||||
|         return self.vm_type.get_location_display() |     #     return self.vm_type.get_location_display() | ||||||
| 
 | 
 | ||||||
|     @cached_property |     @cached_property | ||||||
|     def name(self): |     def name(self): | ||||||
|  | @ -155,24 +164,6 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): | ||||||
|         instance.assign_permissions(user) |         instance.assign_permissions(user) | ||||||
|         return instance |         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): |     def cancel_plan(self): | ||||||
|         self.status = self.CANCELED_STATUS |         self.status = self.CANCELED_STATUS | ||||||
|         self.save(update_fields=['status']) |         self.save(update_fields=['status']) | ||||||
|  | @ -224,6 +215,32 @@ class HostingOrder(AssignPermissionsMixin, models.Model): | ||||||
|         self.save() |         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): | class ManageVM(models.Model): | ||||||
|     def has_add_permission(self, request): |     def has_add_permission(self, request): | ||||||
|         return False |         return False | ||||||
|  |  | ||||||
|  | @ -87,6 +87,48 @@ class HostingManageVMAdmin(admin.ModelAdmin): | ||||||
|         ) |         ) | ||||||
|         return TemplateResponse(request, "hosting/managevms.html", context) |         return TemplateResponse(request, "hosting/managevms.html", context) | ||||||
| 
 | 
 | ||||||
|  |     def create_vm_view(self, specs): | ||||||
|  |         vm_id = None | ||||||
|  |         try: | ||||||
|  |             # We do have the vm_template param set. Get and parse it | ||||||
|  |             # and check it to be in the desired range. | ||||||
|  |             # We have 8 possible VM templates for the moment which are 1x, 2x, 4x ... | ||||||
|  |             # the basic template of 10GB disk, 1GB ram, 1 vcpu, 0.1 cpu | ||||||
|  |             vm_string_formatter = """<VM> | ||||||
|  |                                       <MEMORY>{memory}</MEMORY> | ||||||
|  |                                       <VCPU>{vcpu}</VCPU> | ||||||
|  |                                       <CPU>{cpu}</CPU> | ||||||
|  |                                       <DISK> | ||||||
|  |                                         <TYPE>{disk_type}</TYPE> | ||||||
|  |                                         <SIZE>{size}</SIZE> | ||||||
|  |                                       </DISK> | ||||||
|  |                                     </VM> | ||||||
|  |                                     """ | ||||||
|  |             vm_id = oca.VirtualMachine.allocate( | ||||||
|  |                 self.client, | ||||||
|  |                 vm_string_formatter.format( | ||||||
|  |                     memory=1024 * specs.get('memory'), | ||||||
|  |                     vcpu=specs.get('cores'), | ||||||
|  |                     cpu=0.1 * specs.get('cores'), | ||||||
|  |                     disk_type='fs', | ||||||
|  |                     size=10000 * specs.get('disk_size') | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |                 # message = _("Created with id = " + str(vm_id)) | ||||||
|  |                 # messages.add_message(request, messages.SUCCESS, message) | ||||||
|  |         except socket.timeout as socket_err: | ||||||
|  |             logger.error("Socket timeout error: {0}".format(socket_err)) | ||||||
|  |         except OpenNebulaException as opennebula_err: | ||||||
|  |             logger.error("OpenNebulaException error: {0}".format(opennebula_err)) | ||||||
|  |         except OSError as os_err: | ||||||
|  |             logger.error("OSError : {0}".format(os_err)) | ||||||
|  |         except ValueError as value_err: | ||||||
|  |             logger.error("ValueError : {0}".format(value_err)) | ||||||
|  | 
 | ||||||
|  |         return vm_id | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     # Creating VM by using method allocate(client, template) |     # Creating VM by using method allocate(client, template) | ||||||
|     def create_vm(self, request): |     def create_vm(self, request): | ||||||
|         # check if the request contains the template parameter, if it is |         # check if the request contains the template parameter, if it is | ||||||
|  |  | ||||||
|  | @ -72,6 +72,11 @@ | ||||||
|                                 <i class="fa fa-credit-card"></i> {% trans "My Orders"%} |                                 <i class="fa fa-credit-card"></i> {% trans "My Orders"%} | ||||||
|                             </a> |                             </a> | ||||||
|                         </li> |                         </li> | ||||||
|  |                         <li> | ||||||
|  |                             <a href="{% url 'hosting:key_pair' %}"> | ||||||
|  |                                 <i class="fa fa-key" aria-hidden="true"></i> {% trans "Keys"%} | ||||||
|  |                             </a> | ||||||
|  |                         </li> | ||||||
|                         <li> |                         <li> | ||||||
|                             <a href="{% url 'hosting:notifications' %}"> |                             <a href="{% url 'hosting:notifications' %}"> | ||||||
|                                 <i class="fa fa-bell"></i> {% trans "Notifications "%} |                                 <i class="fa fa-bell"></i> {% trans "Notifications "%} | ||||||
|  |  | ||||||
							
								
								
									
										45
									
								
								hosting/templates/hosting/create_virtual_machine.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								hosting/templates/hosting/create_virtual_machine.html
									
										
									
									
									
										Normal 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: | ||||||
|  |                         <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%} | ||||||
|  | @ -24,58 +24,17 @@ | ||||||
|                 {% csrf_token %} |                 {% csrf_token %} | ||||||
|                 <input type="hidden" name="hosting_company" value="{{vm.hosting_company}}"> |                 <input type="hidden" name="hosting_company" value="{{vm.hosting_company}}"> | ||||||
|                 <input type="hidden" name="location_code" value="{{vm.location_code}}"> |                 <input type="hidden" name="location_code" value="{{vm.location_code}}"> | ||||||
|  |                 <input type="hidden" name="vm_template" value="{{vm.id}}"> | ||||||
|                 |                 | ||||||
|                  |                  | ||||||
|                  |                  | ||||||
|                 <ul class="pricing {% cycle 'p-red' 'p-black' 'p-red' 'p-yel' %}"> |                 <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> |                   <li> | ||||||
|                     <!-- Single button --> |                     <!-- Single button --> | ||||||
|                     <div class="btn-group"> |                     <div class="btn-group"> | ||||||
|                       <div class="form-group"> |                       <div class="form-group"> | ||||||
|                         <label for="cores">Location: </label> |                         <label for="cores">Cores: {{vm.cores}}</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> |  | ||||||
|                       </div> |                       </div> | ||||||
|                     </div> |                     </div> | ||||||
| 
 | 
 | ||||||
|  | @ -83,30 +42,28 @@ | ||||||
|                   <li> |                   <li> | ||||||
|                     <div class="form-group"> |                     <div class="form-group"> | ||||||
|                       <div class="btn-group"> |                       <div class="btn-group"> | ||||||
|                         <label for="memory">Memory: </label>  |                         <label for="memory">Memory: {{vm.memory}} GiB</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> |  | ||||||
|                       </div> |                       </div> | ||||||
|                     </div> |                     </div> | ||||||
|                   </li>            |                   </li>            | ||||||
|                   <li> |                   <li> | ||||||
|                     <div class="form-group row"> |                     <div class="form-group row"> | ||||||
|                       <div class="col-xs-offset-1 col-xs-9 col-sm-12 col-md-12 col-md-offset-0"> |                       <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> |                         <label for="Disk Size">Disk Size: {{vm.disk_size}} GiB</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> |  | ||||||
|                       </div> |                       </div> | ||||||
|                     </div> |                     </div> | ||||||
|                   </li> |                   </li> | ||||||
|                   <li> |                   <li> | ||||||
|                     <input id="{{vm.hosting_company}}-final-price-input" type="hidden" name="final_price" value="{{vm.default_price|floatformat}}"> |                   <label for="configuration">Configuration: </label> | ||||||
|                     <h3 id="{{vm.hosting_company}}-final-price">{{vm.default_price|floatformat}}CHF</h3> |                         <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> |                     <span>per month</span> | ||||||
|                   </li> |                   </li> | ||||||
|                   <li> |                   <li> | ||||||
|  |  | ||||||
|  | @ -65,7 +65,7 @@ | ||||||
|             {% url 'hosting:payment' as payment_url %} |             {% url 'hosting:payment' as payment_url %} | ||||||
|             {% if payment_url in request.META.HTTP_REFERER  %} |             {% if payment_url in request.META.HTTP_REFERER  %} | ||||||
|             <div class=" content pull-right"> |             <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> |             </div> | ||||||
|             {% endif %} |             {% endif %} | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|  | @ -86,11 +86,11 @@ | ||||||
| 							<h3><b>Billing Amount</b></h3> | 							<h3><b>Billing Amount</b></h3> | ||||||
| 							<hr> | 							<hr> | ||||||
| 							<div class="content"> | 							<div class="content"> | ||||||
| 								<p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.location_code}}</span></p> | 								<!-- <p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.location_code}}</span></p> --> | ||||||
| 								<hr> | 								<!-- <hr> --> | ||||||
| 								<p><b>Cores</b> <span class="pull-right">{{request.session.vm_specs.cores}}</span></p> | 								<p><b>Cores</b> <span class="pull-right">{{request.session.vm_specs.cores}}</span></p> | ||||||
| 								<hr> | 								<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>								 | 								<hr>								 | ||||||
| 								<p><b>Memory</b> <span class="pull-right">{{request.session.vm_specs.memory}} GiB</span></p> | 								<p><b>Memory</b> <span class="pull-right">{{request.session.vm_specs.memory}} GiB</span></p> | ||||||
| 								<hr> | 								<hr> | ||||||
|  |  | ||||||
|  | @ -6,30 +6,75 @@ | ||||||
| 		<div class="row"> | 		<div class="row"> | ||||||
| 			<div class="col-md-9 col-md-offset-2"> | 			<div class="col-md-9 col-md-offset-2"> | ||||||
| 				 <div  class="col-sm-12"> | 				 <div  class="col-sm-12"> | ||||||
| 
 |                     <form method="POST" action="" > | ||||||
| 				        <h3><i class="fa fa-key" aria-hidden="true"></i>{% trans "SSH Private Key"%} </h3> |                         {% csrf_token %} | ||||||
|  | 				        <h3><i class="fa fa-key" aria-hidden="true"></i>{% trans "Access Key"%} </h3> | ||||||
| 				        <hr/>	 | 				        <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 %} | 				        {% if private_key %} | ||||||
| 				 		<div class="alert alert-warning"> | 				 		<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."%}   |   							<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> | ||||||
| 						<div class="form-group"> | 						<div class="form-group"> | ||||||
| 						  <label for="comment">private_key.pem</label> | 						  <textarea class="form-control" rows="6" id="ssh_key" type="hidden" style="display:none">{{private_key}}</textarea> | ||||||
| 						  <textarea class="form-control" rows="6" id="ssh_key">{{private_key}}</textarea> |  | ||||||
| 
 | 
 | ||||||
| 						</div> | 						</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" | 								<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> | 									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>   | 								<button type="button" id="download_ssh_key" class="btn btn-warning">{% trans "Download"%}</button>   | ||||||
| 							</div>				         | 							</div> -->				         | ||||||
| 						{% else %} | 						{% 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. "%}  | 	  							<strong>{% trans "Warning!"%}</strong>{% trans "Your SSH private key was already generated and downloaded, if you lost it, contact us. "%}  | ||||||
| 							</div> | 							</div> | ||||||
| 						{% endif %} |  -->						{% endif %} | ||||||
| 						<a class="btn btn-success" href="{% url 'hosting:virtual_machines' virtual_machine.id %}">{% trans "Go to my Virtual Machine Dashboard"%} </a> | 						<!-- <a class="btn btn-success" href="{% url 'hosting:virtual_machines' %}">{% trans "Generate my key"%} </a> --> | ||||||
| 						<div class="clearfix"></div> | 						<div class="clearfix"></div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
|  | @ -42,11 +87,12 @@ | ||||||
| <!-- Force to download ssh key on page load --> | <!-- Force to download ssh key on page load --> | ||||||
| <script type="text/javascript">  | <script type="text/javascript">  | ||||||
| 
 | 
 | ||||||
| 		var key = window.document.getElementById('ssh_key'); |         var key = window.document.getElementById('ssh_key'); | ||||||
|  | 
 | ||||||
| 		var a = window.document.createElement('a'); | 		var a = window.document.createElement('a'); | ||||||
| 
 | 
 | ||||||
| 		a.href = window.URL.createObjectURL(new Blob(['key'], {type: 'text'})); | 		a.href = window.URL.createObjectURL(new Blob([key.value], {type: 'text'})); | ||||||
| 		a.download = 'private_key.pem'; | 		a.download = '{{key_name}}.pem'; | ||||||
| 
 | 
 | ||||||
| 		// Append anchor to body. | 		// Append anchor to body. | ||||||
| 		document.body.appendChild(a); | 		document.body.appendChild(a); | ||||||
|  |  | ||||||
|  | @ -6,12 +6,14 @@ | ||||||
| 		<div class="row"> | 		<div class="row"> | ||||||
| 			<div class="col-md-8 col-md-offset-2"> | 			<div class="col-md-8 col-md-offset-2"> | ||||||
| 				<table class="table borderless table-hover">  | 				<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/> | 				<br/> | ||||||
| 				<thead>  | 				<thead>  | ||||||
| 				<tr>  | 				<tr>  | ||||||
| 					<th>{% trans "ID"%}</th> | 					<th>{% trans "ID"%}</th> | ||||||
| 					<th>{% trans "Location"%} </th> |  | ||||||
| 					<th>{% trans "Amount"%}</th> | 					<th>{% trans "Amount"%}</th> | ||||||
| 					<th>{% trans "Status"%}</th> | 					<th>{% trans "Status"%}</th> | ||||||
| 					<th></th> | 					<th></th> | ||||||
|  | @ -21,7 +23,6 @@ | ||||||
| 					{% for vm in vms %} | 					{% for vm in vms %} | ||||||
| 					<tr>  | 					<tr>  | ||||||
| 						<td scope="row">{{vm.name}}</td>  | 						<td scope="row">{{vm.name}}</td>  | ||||||
| 						<td>{{vm.location}}</td>  |  | ||||||
| 						<td>{{vm.price}} CHF</td>  | 						<td>{{vm.price}} CHF</td>  | ||||||
| 						<td> | 						<td> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,7 +4,8 @@ from .views import DjangoHostingView, RailsHostingView, PaymentVMView,\ | ||||||
|     NodeJSHostingView, LoginView, SignupView, IndexView, \ |     NodeJSHostingView, LoginView, SignupView, IndexView, \ | ||||||
|     OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\ |     OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\ | ||||||
|     VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \ |     VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \ | ||||||
|     MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView |     MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView,\ | ||||||
|  |     CreateVirtualMachinesView | ||||||
| 
 | 
 | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|     url(r'index/?$', IndexView.as_view(), name='index'), |     url(r'index/?$', IndexView.as_view(), name='index'), | ||||||
|  | @ -16,13 +17,14 @@ urlpatterns = [ | ||||||
|     url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'), |     url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'), | ||||||
|     url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.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'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/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'), | ||||||
|     url(r'my-virtual-machines/(?P<pk>\d+)/?$', VirtualMachineView.as_view(), |     url(r'my-virtual-machines/(?P<pk>\d+)/?$', VirtualMachineView.as_view(), | ||||||
|         name='virtual_machines'), |         name='virtual_machines'), | ||||||
|     # url(r'my-virtual-machines/(?P<pk>\d+)/delete/?$', VirtualMachineCancelView.as_view(), |     # url(r'my-virtual-machines/(?P<pk>\d+)/delete/?$', VirtualMachineCancelView.as_view(), | ||||||
|         # name='virtual_machines_cancel'), |         # name='virtual_machines_cancel'), | ||||||
|     url(r'my-virtual-machines/(?P<pk>\d+)/key/?$', GenerateVMSSHKeysView.as_view(), |     url(r'vm-key-pair/?$', GenerateVMSSHKeysView.as_view(), | ||||||
|         name='virtual_machine_key'), |         name='key_pair'), | ||||||
|     url(r'^notifications/$', NotificationsView.as_view(), name='notifications'), |     url(r'^notifications/$', NotificationsView.as_view(), name='notifications'), | ||||||
|     url(r'^notifications/(?P<pk>\d+)/?$', MarkAsReadNotificationView.as_view(), |     url(r'^notifications/(?P<pk>\d+)/?$', MarkAsReadNotificationView.as_view(), | ||||||
|         name='read_notification'), |         name='read_notification'), | ||||||
|  |  | ||||||
							
								
								
									
										133
									
								
								hosting/views.py
									
										
									
									
									
								
							
							
						
						
									
										133
									
								
								hosting/views.py
									
										
									
									
									
								
							|  | @ -1,3 +1,4 @@ | ||||||
|  | from collections import namedtuple | ||||||
| 
 | 
 | ||||||
| from django.shortcuts import render | from django.shortcuts import render | ||||||
| from django.core.urlresolvers import reverse_lazy, reverse | from django.core.urlresolvers import reverse_lazy, reverse | ||||||
|  | @ -7,6 +8,8 @@ from django.views.generic import View, CreateView, FormView, ListView, DetailVie | ||||||
| from django.http import HttpResponseRedirect | from django.http import HttpResponseRedirect | ||||||
| from django.contrib.auth import authenticate, login | from django.contrib.auth import authenticate, login | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
|  | from django.shortcuts import redirect | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| from guardian.mixins import PermissionRequiredMixin | from guardian.mixins import PermissionRequiredMixin | ||||||
| from stored_messages.settings import stored_messages_settings | from stored_messages.settings import stored_messages_settings | ||||||
|  | @ -14,14 +17,16 @@ from stored_messages.models import Message | ||||||
| from stored_messages.api import mark_read | from stored_messages.api import mark_read | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| from membership.models import CustomUser, StripeCustomer | from membership.models import CustomUser, StripeCustomer | ||||||
| from utils.stripe_utils import StripeUtils | from utils.stripe_utils import StripeUtils | ||||||
| from utils.forms import BillingAddressForm, PasswordResetRequestForm | from utils.forms import BillingAddressForm, PasswordResetRequestForm | ||||||
| from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin | from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin | ||||||
| from utils.mailer import BaseEmail | from utils.mailer import BaseEmail | ||||||
| from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder | from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, UserHostingKey | ||||||
| from .forms import HostingUserSignupForm, HostingUserLoginForm | from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyForm | ||||||
| from .mixins import ProcessVMSelectionMixin | from .mixins import ProcessVMSelectionMixin | ||||||
|  | from .opennebula_functions import HostingManageVMAdmin | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class DjangoHostingView(ProcessVMSelectionMixin, View): | class DjangoHostingView(ProcessVMSelectionMixin, View): | ||||||
|  | @ -38,6 +43,7 @@ class DjangoHostingView(ProcessVMSelectionMixin, View): | ||||||
|             'google_analytics': "UA-62285904-6", |             'google_analytics': "UA-62285904-6", | ||||||
|             'email': "info@django-hosting.ch", |             'email': "info@django-hosting.ch", | ||||||
|             'vm_types': VirtualMachineType.get_serialized_vm_types(), |             'vm_types': VirtualMachineType.get_serialized_vm_types(), | ||||||
|  |             'configuration_options': dict(VirtualMachinePlan.VM_CONFIGURATION) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return context |         return context | ||||||
|  | @ -206,26 +212,52 @@ class MarkAsReadNotificationView(LoginRequiredMixin, UpdateView): | ||||||
|         return HttpResponseRedirect(reverse('hosting:notifications')) |         return HttpResponseRedirect(reverse('hosting:notifications')) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class GenerateVMSSHKeysView(LoginRequiredMixin, DetailView): | class GenerateVMSSHKeysView(LoginRequiredMixin, FormView): | ||||||
|     model = VirtualMachinePlan |     form_class = UserHostingKeyForm | ||||||
|  |     model = UserHostingKey | ||||||
|     template_name = 'hosting/virtual_machine_key.html' |     template_name = 'hosting/virtual_machine_key.html' | ||||||
|     success_url = reverse_lazy('hosting:orders') |     success_url = reverse_lazy('hosting:orders') | ||||||
|     login_url = reverse_lazy('hosting:login') |     login_url = reverse_lazy('hosting:login') | ||||||
|     context_object_name = "virtual_machine" |     context_object_name = "virtual_machine" | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     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 |         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): | class PaymentVMView(LoginRequiredMixin, FormView): | ||||||
|     template_name = 'hosting/payment.html' |     template_name = 'hosting/payment.html' | ||||||
|  | @ -246,18 +278,26 @@ class PaymentVMView(LoginRequiredMixin, FormView): | ||||||
|         if form.is_valid(): |         if form.is_valid(): | ||||||
|             context = self.get_context_data() |             context = self.get_context_data() | ||||||
|             specifications = request.session.get('vm_specs') |             specifications = request.session.get('vm_specs') | ||||||
|             vm_type = specifications.get('hosting_company') | 
 | ||||||
|             vm = VirtualMachineType.objects.get(hosting_company=vm_type) |             vm_template = specifications.get('vm_template', 1) | ||||||
|             final_price = vm.calculate_price(specifications) | 
 | ||||||
|  |             vm_type = VirtualMachineType.objects.get(id=vm_template) | ||||||
|  | 
 | ||||||
|  |             specs = vm_type.get_specs() | ||||||
|  | 
 | ||||||
|  |             final_price = vm_type.calculate_price() | ||||||
| 
 | 
 | ||||||
|             plan_data = { |             plan_data = { | ||||||
|                 'vm_type': vm, |                 'vm_type': vm_type, | ||||||
|                 'cores': specifications.get('cores'), |                 'configuration': specifications.get( | ||||||
|                 'memory': specifications.get('memory'), |                     'configuration', | ||||||
|                 'disk_size': specifications.get('disk_size'), |                     'django' | ||||||
|                 'configuration': specifications.get('configuration'), |                 ), | ||||||
|                 'price': final_price |                 'price': final_price | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             plan_data.update(specs) | ||||||
|  | 
 | ||||||
|             token = form.cleaned_data.get('token') |             token = form.cleaned_data.get('token') | ||||||
| 
 | 
 | ||||||
|             # Get or create stripe customer |             # Get or create stripe customer | ||||||
|  | @ -299,6 +339,20 @@ class PaymentVMView(LoginRequiredMixin, FormView): | ||||||
|             # If the Stripe payment was successed, set order status approved |             # If the Stripe payment was successed, set order status approved | ||||||
|             order.set_approved() |             order.set_approved() | ||||||
| 
 | 
 | ||||||
|  |             # Create VM using oppenebula functions  | ||||||
|  |             # _request = namedtuple('request', 'POST user') | ||||||
|  |             # _request.user = request.user | ||||||
|  |             # user = namedtuple('user', 'email') | ||||||
|  |             # email  | ||||||
|  |             # _request.POST = { | ||||||
|  |                 # 'vm_template': vm_template | ||||||
|  |             # } | ||||||
|  | 
 | ||||||
|  |             hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin) | ||||||
|  |             hosting_admin.init_opennebula_client(request) | ||||||
|  |             oppennebula_vm_id = hosting_admin.create_vm_view(vm_type.get_specs()) | ||||||
|  |             plan.oppenebula_id = oppennebula_vm_id | ||||||
|  | 
 | ||||||
|             # Send notification to ungleich as soon as VM has been booked |             # Send notification to ungleich as soon as VM has been booked | ||||||
|             context = { |             context = { | ||||||
|                 'vm': plan, |                 'vm': plan, | ||||||
|  | @ -358,11 +412,48 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView): | ||||||
|     ordering = '-id' |     ordering = '-id' | ||||||
| 
 | 
 | ||||||
|     def get_queryset(self): |     def get_queryset(self): | ||||||
|  |         hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin) | ||||||
|  |         print(hosting_admin.show_vms(self.request)) | ||||||
|         user = self.request.user |         user = self.request.user | ||||||
|         self.queryset = VirtualMachinePlan.objects.active(user) |         self.queryset = VirtualMachinePlan.objects.active(user) | ||||||
|         return super(VirtualMachinesPlanListView, self).get_queryset() |         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 | ||||||
|  |         }) | ||||||
|  |         request.session['vm_specs'] = vm_specs | ||||||
|  |         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): | class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, UpdateView): | ||||||
|     template_name = "hosting/virtual_machine_detail.html" |     template_name = "hosting/virtual_machine_detail.html" | ||||||
|     login_url = reverse_lazy('hosting:login') |     login_url = reverse_lazy('hosting:login') | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue