From f142bb1ce980e68419ac67d57e2b9af2d2079529 Mon Sep 17 00:00:00 2001 From: modulos Date: Mon, 29 May 2017 15:00:47 +0200 Subject: [PATCH 01/10] Move keys section underneath user name menu --- hosting/templates/hosting/base_short.html | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hosting/templates/hosting/base_short.html b/hosting/templates/hosting/base_short.html index c6d1772e..4a1a95be 100644 --- a/hosting/templates/hosting/base_short.html +++ b/hosting/templates/hosting/base_short.html @@ -72,11 +72,7 @@ {% trans "My Orders"%} -
  • - - {% trans "Keys"%} - -
  • +
  • {% trans "Notifications "%} @@ -87,6 +83,11 @@ {{request.user.name}}
  • {% else %} From 0b5cf2c057c4636bc9e7789a25739dcf2e2f8cc8 Mon Sep 17 00:00:00 2001 From: modulos Date: Wed, 31 May 2017 18:01:54 +0200 Subject: [PATCH 02/10] Cleanup and add tests --- opennebula_api/models.py | 133 ++++++++++++++++++++++++++++++- opennebula_api/tests.py | 166 +++++++++++++++------------------------ 2 files changed, 192 insertions(+), 107 deletions(-) diff --git a/opennebula_api/models.py b/opennebula_api/models.py index 3eac0b6e..423013e4 100644 --- a/opennebula_api/models.py +++ b/opennebula_api/models.py @@ -2,12 +2,14 @@ import oca import socket import logging +from oca.pool import WrongNameError +from oca.exceptions import OpenNebulaException from django.conf import settings from django.utils.functional import cached_property -from oca.pool import WrongNameError -from oca.exceptions import OpenNebulaException +from utils.models import CustomUser + logger = logging.getLogger(__name__) @@ -35,10 +37,33 @@ class OpenNebulaManager(): ) except: pass + def _get_client(self, user): + """Get a opennebula client object for a CustomUser object + + Args: + user (CustomUser): dynamicweb CustomUser object + + Returns: + oca.Client: Opennebula client object + + Raise: + ConnectionError: If the connection to the opennebula server can't be + established + """ + return oca.Client("{0}:{1}".format( + user.email, + user.password), + "{protocol}://{domain}:{port}{endpoint}".format( + protocol=settings.OPENNEBULA_PROTOCOL, + domain=settings.OPENNEBULA_DOMAIN, + port=settings.OPENNEBULA_PORT, + endpoint=settings.OPENNEBULA_ENDPOINT + )) def _get_opennebula_client(self, username, password): return oca.Client("{0}:{1}".format( username, + password), "{protocol}://{domain}:{port}{endpoint}".format( protocol=settings.OPENNEBULA_PROTOCOL, @@ -47,6 +72,69 @@ class OpenNebulaManager(): endpoint=settings.OPENNEBULA_ENDPOINT )) + def _get_user(self, user): + """Get the corresponding opennebula user for a CustomUser object + + Args: + user (CustomUser): dynamicweb CustomUser object + + Returns: + oca.User: Opennebula user object + + Raise: + WrongNameError: If no openebula user with this credentials exists + ConnectionError: If the connection to the opennebula server can't be + established + """ + user_pool = self._get_user_pool() + return user_pool.get_by_name(user.email) + + def create_user(self, user: CustomUser): + """Create a new opennebula user or a corresponding CustomUser object + + + Args: + user (CustomUser): dynamicweb CustomUser object + + Returns: + int: Return the opennebula user id + + Raises: + ConnectionError: If the connection to the opennebula server can't be + established + UserExistsError: If a user with this credeintals already exits on the + server + UserCredentialError: If a user with this email exists but the + password is worng + + """ + try: + self._get_user(user) + try: + self._get_client(self, user) + logger.debug('User already exists') + raise UserExistsError() + except OpenNebulaException as err: + logger.error('OpenNebulaException error: {0}'.format(err)) + logger.debug('User exists but password is wrong') + raise UserCredentialError() + + except WrongNameError: + user_id = self.oneadmin_client.call(oca.User.METHODS['allocate'], + user.email, user.password, 'core') + logger.debug('Created a user for CustomObject: {user} with user id = {u_id}', + user=user, + u_id=user_id + ) + return user_id + except ConnectionRefusedError: + logger.error('Could not connect to host: {host} via protocol {protocol}'.format( + host=settings.OPENNEBULA_DOMAIN, + protocol=settings.OPENNEBULA_PROTOCOL) + ) + raise ConnectionRefusedError + + def _get_or_create_user(self, email, password): try: user_pool = self._get_user_pool() @@ -77,7 +165,7 @@ class OpenNebulaManager(): host=settings.OPENNEBULA_DOMAIN, protocol=settings.OPENNEBULA_PROTOCOL) ) - raise ConnectionRefusedError + raise return user_pool def _get_vm_pool(self): @@ -350,3 +438,42 @@ class OpenNebulaManager(): self.opennebula_user.id, new_password ) + + def add_public_key(self, user, public_key='', replace=True): + """ + + Args: + user (CustomUser): Dynamicweb user + public_key (string): Public key to add to the user + replace (bool): Optional if True the new public key replaces the old + + Raises: + KeyExistsError: If replace is False and the user already has a + public key + WrongNameError: If no openebula user with this credentials exists + ConnectionError: If the connection to the opennebula server can't be + established + + Returns: + True if public_key was added + + """ + # TODO: Check if we can remove this first try because we basically just + # raise the possible Errors + try: + open_user = self._get_user(user) + try: + old_key = open_user.template.ssh_public_key + if not replace: + raise KeyExistsError() + + except AttributeError: + pass + self.oneadmin_client.call('user.update', open_user.id, + '{key}'.format(key=public_key)) + return True + except WrongNameError: + raise + + except ConnectionError: + raise diff --git a/opennebula_api/tests.py b/opennebula_api/tests.py index 14694e6f..bd744a66 100644 --- a/opennebula_api/tests.py +++ b/opennebula_api/tests.py @@ -1,35 +1,53 @@ +import socket +import random +import string + from django.test import TestCase -from .models import VirtualMachine, VirtualMachineTemplate, OpenNebulaManager + +from .models import OpenNebulaManager +from utils.models import CustomUser class OpenNebulaManagerTestCases(TestCase): """This class defines the test suite for the opennebula manager model.""" def setUp(self): """Define the test client and other test variables.""" - self.cores = 1 - self.memory = 1 - self.disk_size = 10.0 - self.email = 'test@test.com' - self.password = 'testtest' - self.manager = OpenNebulaManager(email=None, password=None, create_user=False) + self.email = '{}@ungleich.ch'.format(''.join(random.choices(string.ascii_uppercase, k=10))) + self.password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=20)) + + self.user = CustomUser.objects.create(name='test', email=self.email, + password=self.password) + + self.vm_specs = {} + self.vm_specs['cpu'] = 1 + self.vm_specs['memory'] = 2 + self.vm_specs['disk_size'] = 10 + + self.manager = OpenNebulaManager() - def test_model_can_connect_to_server(self): - """Test the opennebula manager model can connect to a server.""" + def test_connect_to_server(self): + """Test the opennebula manager can connect to a server.""" try: - user_pool = self.manager._get_user_pool() - except: - user_pool = None - self.assertFalse(user_pool is None) + ver = self.manager.oneadmin_client.version() + except: + ver = None + self.assertTrue(ver is not None) - def test_model_can_create_user(self): - """Test the opennebula manager model can create a new user.""" + def test_get_user(self): + """Test the opennebula manager can get a existing user.""" + self.manager.create_user(self.user) + user = self.manager._get_user(self.user) + name = user.name + self.assertNotEqual(name, None) + + def test_create_and_delete_user(self): + """Test the opennebula manager can create and delete a new user.""" old_count = len(self.manager._get_user_pool()) self.manager = OpenNebulaManager(email=self.email, - password=self.password, - create_user=True) + password=self.password) user_pool = self.manager._get_user_pool() new_count = len(user_pool) # Remove the user afterwards @@ -38,96 +56,36 @@ class OpenNebulaManagerTestCases(TestCase): self.assertNotEqual(old_count, new_count) + def test_user_can_login(self): + """ Test the manager can login to a new created user""" + self.manager.create_user(self.user) + user = self.manager._get_user(self.user) + client = self.manager._get_client(self.user) + version = client.version() -class VirtualMachineTemplateTestCase(TestCase): - """This class defines the test suite for the virtualmachine template model.""" + # Cleanup + user.delete() + self.assertNotEqual(version, None) - def setUp(self): - """Define the test client and other test variables.""" - self.template_name = "Standard" - self.base_price = 0.0 - self.core_price = 5.0 - self.memory_price = 2.0 - self.disk_size_price = 0.6 + def test_add_public_key_to_user(self): + """ Test the manager can add a new public key to an user """ + self.manager.create_user(self.user) + user = self.manager._get_user(self.user) + public_key = 'test' + self.manager.add_public_key(self.user, public_key) + # Fetch new user information from opennebula + user.info() + user_public_key = user.template.ssh_public_key + # Cleanup + user.delete() - self.cores = 1 - self.memory = 1 - self.disk_size = 10.0 - - self.manager = OpenNebulaManager(email=None, password=None, create_user=False) - self.opennebula_id = self.manager.create_template(name=self.template_name, - cores=self.cores, - memory=self.memory, - disk_size=self.disk_size) - - self.template = VirtualMachineTemplate(opennebula_id=self.opennebula_id, - base_price=self.base_price, - memory_price=self.memory_price, - core_price=self.core_price, - disk_size_price=self.disk_size_price) - - - def test_model_can_create_a_virtualmachine_template(self): - """Test the virtualmachine template model can create a template.""" - old_count = VirtualMachineTemplate.objects.count() - self.template.save() - new_count = VirtualMachineTemplate.objects.count() - # Remove the template afterwards - template = self.manager._get_template(self.template.opennebula_id) - template.delete() - self.assertNotEqual(old_count, new_count) - - def test_model_can_calculate_price(self): - price = self.cores * self.core_price - price += self.memory * self.memory_price - price += self.disk_size * self.disk_size_price - self.assertEqual(price, self.template.calculate_price()) - - - -class VirtualMachineTestCase(TestCase): - def setUp(self): - """Define the test client and other test variables.""" - self.template_name = "Standard" - self.base_price = 0.0 - self.core_price = 5.0 - self.memory_price = 2.0 - self.disk_size_price = 0.6 - - self.cores = 1 - self.memory = 1 - self.disk_size = 10.0 - self.manager = OpenNebulaManager(email=None, password=None, create_user=False) - self.opennebula_id = self.manager.create_template(name=self.template_name, - cores=self.cores, - memory=self.memory, - disk_size=self.disk_size) - - self.template = VirtualMachineTemplate(opennebula_id=self.opennebula_id, - base_price=self.base_price, - memory_price=self.memory_price, - core_price=self.core_price, - disk_size_price=self.disk_size_price) - self.template_id = self.template.opennebula_id() - self.opennebula_id = self.manager.create_virtualmachine(template_id=self.template_id) - - self.virtualmachine = VirtualMachine(opennebula_id=self.opennebula_id, - template=self.template) + self.assertEqual(user_public_key, public_key) - def test_model_can_create_a_virtualmachine(self): - """Test the virtualmachine model can create a virtualmachine.""" - old_count = VirtualMachine.objects.count() - self.virtualmachine.save() - new_count = VirtualMachine.objects.count() - self.assertNotEqual(old_count, new_count) - def test_model_can_create_a_virtualmachine_for_user(self): - pass + def test_requires_ssh_key_for_new_vm(self): + """Test the opennebula manager requires the user to have a ssh key when + creating a new vm""" + + + - def test_model_can_delete_a_virtualmachine(self): - """Test the virtualmachine model can delete a virtualmachine.""" - self.virtualmachine.save() - old_count = VirtualMachine.objects.count() - VirtualMachine.objects.first().delete() - new_count = VirtualMachine.objects.count() - self.assertNotEqual(old_count, new_count) From ca63355914892e115b97f958afb4251ae69745fd Mon Sep 17 00:00:00 2001 From: modulos Date: Thu, 1 Jun 2017 17:30:53 +0200 Subject: [PATCH 03/10] Remove templates In the current setup the templates views are not necessary --- opennebula_api/serializers.py | 37 ----------------------------------- opennebula_api/urls.py | 7 +------ opennebula_api/views.py | 32 ------------------------------ 3 files changed, 1 insertion(+), 75 deletions(-) diff --git a/opennebula_api/serializers.py b/opennebula_api/serializers.py index 6c86776a..60ce16f9 100644 --- a/opennebula_api/serializers.py +++ b/opennebula_api/serializers.py @@ -11,37 +11,12 @@ from .models import OpenNebulaManager class VirtualMachineTemplateSerializer(serializers.Serializer): """Serializer to map the virtual machine template instance into JSON format.""" id = serializers.IntegerField(read_only=True) - set_name = serializers.CharField(read_only=True, label='Name') name = serializers.SerializerMethodField() cores = serializers.SerializerMethodField() - disk = serializers.IntegerField(write_only=True) disk_size = serializers.SerializerMethodField() - set_memory = serializers.IntegerField(write_only=True, label='Memory') memory = serializers.SerializerMethodField() price = serializers.SerializerMethodField() - def create(self, validated_data): - data = validated_data - template = data.pop('template') - - cores = template.pop('vcpu') - name = data.pop('name') - disk_size = data.pop('disk') - memory = template.pop('memory') - manager = OpenNebulaManager() - - try: - opennebula_id = manager.create_template(name=name, cores=cores, - memory=memory, - disk_size=disk_size, - core_price=core_price, - disk_size_price=disk_size_price, - memory_price=memory_price) - except OpenNebulaException as err: - raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err)) - - return manager.get_template(template_id=opennebula_id) - def get_cores(self, obj): if hasattr(obj.template, 'vcpu'): return obj.template.vcpu @@ -58,18 +33,6 @@ class VirtualMachineTemplateSerializer(serializers.Serializer): except: return 0 - - def get_price(self, obj): - template = obj.template - price = float(template.cpu) * 5.0 - price += (int(template.memory)/1024 * 2.0) - try: - for disk in template.disks: - price += int(disk.size)/1024 * 0.6 - except: - pass - return price - def get_memory(self, obj): return int(obj.template.memory)/1024 diff --git a/opennebula_api/urls.py b/opennebula_api/urls.py index be5bdbf2..87976e2e 100644 --- a/opennebula_api/urls.py +++ b/opennebula_api/urls.py @@ -1,15 +1,10 @@ from django.conf.urls import url, include from rest_framework.urlpatterns import format_suffix_patterns -from .views import TemplateCreateView, TemplateDetailsView,\ - VmCreateView, VmDetailsView +from .views import VmCreateView, VmDetailsView urlpatterns = { url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^templates/$', TemplateCreateView.as_view(), name="template_create"), - url(r'^templates/(?P[0-9]+)/$', TemplateDetailsView.as_view(), - name="templates_details"), - url(r'^vms/$', VmCreateView.as_view(), name="vm_create"), url(r'^vms/(?P[0-9]+)/$', VmDetailsView.as_view(), name="vm_details"), diff --git a/opennebula_api/views.py b/opennebula_api/views.py index d982f7bb..f6c6b8d7 100644 --- a/opennebula_api/views.py +++ b/opennebula_api/views.py @@ -20,38 +20,6 @@ class ServiceUnavailable(APIException): default_code = 'service_unavailable' -class TemplateCreateView(generics.ListCreateAPIView): - """This class handles the GET and POST requests.""" - - serializer_class = VirtualMachineTemplateSerializer - permission_classes = (permissions.IsAuthenticated, permissions.IsAdminUser) - - def get_queryset(self): - manager = OpenNebulaManager() - return manager.get_templates() - - - def perform_create(self, serializer): - """Save the post data when creating a new template.""" - serializer.save() - -class TemplateDetailsView(generics.RetrieveUpdateDestroyAPIView): - """This class handles the http GET, PUT and DELETE requests.""" - - serializer_class = VirtualMachineTemplateSerializer - permission_classes = (permissions.IsAuthenticated) - - def get_queryset(self): - manager = OpenNebulaManager() - # We may have ConnectionRefusedError if we don't have a - # connection to OpenNebula. For now, we raise ServiceUnavailable - try: - templates = manager.get_templates() - except ConnectionRefusedError: - raise ServiceUnavailable - - return templates - class VmCreateView(generics.ListCreateAPIView): """This class handles the GET and POST requests.""" serializer_class = VirtualMachineSerializer From 0db15d99a5382dcfe6d641c867d15872d0dbf61c Mon Sep 17 00:00:00 2001 From: modulos Date: Thu, 1 Jun 2017 19:08:38 +0200 Subject: [PATCH 04/10] Add exceptions, merge for ssh key The replace variable of the add_public_key function is now a merge variable in order to append new keys to a user --- opennebula_api/exceptions.py | 9 +++++++++ opennebula_api/models.py | 6 ++++-- opennebula_api/tests.py | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 opennebula_api/exceptions.py diff --git a/opennebula_api/exceptions.py b/opennebula_api/exceptions.py new file mode 100644 index 00000000..2fa15b43 --- /dev/null +++ b/opennebula_api/exceptions.py @@ -0,0 +1,9 @@ + +class KeyExistsError(Exception): + pass + +class UserExistsError(Exception): + pass + +class UserCredentialError(Exception): + pass diff --git a/opennebula_api/models.py b/opennebula_api/models.py index 423013e4..052291c1 100644 --- a/opennebula_api/models.py +++ b/opennebula_api/models.py @@ -9,6 +9,7 @@ from django.conf import settings from django.utils.functional import cached_property from utils.models import CustomUser +from .exceptions import KeyExistsError, UserExistsError, UserCredentialError logger = logging.getLogger(__name__) @@ -439,7 +440,7 @@ class OpenNebulaManager(): new_password ) - def add_public_key(self, user, public_key='', replace=True): + def add_public_key(self, user, public_key='', merge=False): """ Args: @@ -464,8 +465,9 @@ class OpenNebulaManager(): open_user = self._get_user(user) try: old_key = open_user.template.ssh_public_key - if not replace: + if not merge: raise KeyExistsError() + public_key += '\n{key}'.format(key=old_key) except AttributeError: pass diff --git a/opennebula_api/tests.py b/opennebula_api/tests.py index bd744a66..0d6ed4eb 100644 --- a/opennebula_api/tests.py +++ b/opennebula_api/tests.py @@ -81,6 +81,23 @@ class OpenNebulaManagerTestCases(TestCase): self.assertEqual(user_public_key, public_key) + def test_append_public_key_to_user(self): + """ Test the manager can append a new public key to an user """ + self.manager.create_user(self.user) + user = self.manager._get_user(self.user) + public_key = 'test' + self.manager.add_public_key(self.user, public_key) + # Fetch new user information from opennebula + user.info() + old_public_key = user.template.ssh_public_key + self.manager.add_public_key(self.user, public_key, merge=True) + user.info() + new_public_key = user.template.ssh_public_key + # Cleanup + user.delete() + + self.assertEqual(new_public_key, '{}\n{}'.format(old_public_key, + public_key)) def test_requires_ssh_key_for_new_vm(self): """Test the opennebula manager requires the user to have a ssh key when From 06f372e56d4552bbf80367bcac09e73e2a304529 Mon Sep 17 00:00:00 2001 From: modulos Date: Thu, 1 Jun 2017 22:25:10 +0200 Subject: [PATCH 05/10] Fix tests, add remove_public_key The tests for VitualMachineSerializer were wrong. The manager now contains a function to remove public keys from a user --- opennebula_api/models.py | 42 +++++++++++++++++++++++++++++++++ opennebula_api/tests.py | 51 ++++++++++------------------------------ 2 files changed, 54 insertions(+), 39 deletions(-) diff --git a/opennebula_api/models.py b/opennebula_api/models.py index 7872f6fc..4fa5d011 100644 --- a/opennebula_api/models.py +++ b/opennebula_api/models.py @@ -479,3 +479,45 @@ class OpenNebulaManager(): except ConnectionError: raise + + def remove_public_key(self, user, public_key=''): + """ + + Args: + user (CustomUser): Dynamicweb user + public_key (string): Public key to be removed to the user + + Raises: + KeyDoesNotExistsError: If replace is False and the user already has a + public key + WrongNameError: If no openebula user with this credentials exists + ConnectionError: If the connection to the opennebula server can't be + established + + Returns: + True if public_key was removed + + """ + + try: + open_user = self._get_user(user) + try: + old_key = open_user.template.ssh_public_key + if public_key not in old_key: + raise KeyDoesNotExistsError() + if '\n{}'.format(public_key) in old_key: + public_key = old_key.replace('\n{}'.format(public_key), '') + else: + public_key = old_key.replace(public_key, '') + + except AttributeError: + raise KeyDoesNotExistsError() + + self.oneadmin_client.call('user.update', open_user.id, + '{key}'.format(key=public_key)) + return True + except WrongNameError: + raise + + except ConnectionError: + raise diff --git a/opennebula_api/tests.py b/opennebula_api/tests.py index 073eb0b9..12b396fe 100644 --- a/opennebula_api/tests.py +++ b/opennebula_api/tests.py @@ -5,6 +5,7 @@ import string from django.test import TestCase from .models import OpenNebulaManager +from .serializers import VirtualMachineSerializer from utils.models import CustomUser class OpenNebulaManagerTestCases(TestCase): @@ -105,6 +106,8 @@ class OpenNebulaManagerTestCases(TestCase): user = self.manager._get_user(self.user) public_key = 'test' self.manager.add_public_key(self.user, public_key) + self.manager.add_public_key(self.user, public_key, merge=True) + user.info() old_public_key = user.template.ssh_public_key self.manager.remove_public_key(self.user, public_key) user.info() @@ -112,7 +115,8 @@ class OpenNebulaManagerTestCases(TestCase): # Cleanup user.delete() - self.assertEqual(new_public_key, old_public_key.replace(public_key, '')) + self.assertEqual(new_public_key, + old_public_key.replace('{}\n'.format(public_key), '', 1)) def test_requires_ssh_key_for_new_vm(self): @@ -120,49 +124,18 @@ class OpenNebulaManagerTestCases(TestCase): creating a new vm""" -class VirtualMachineTestCase(TestCase): +class VirtualMachineSerializerTestCase(TestCase): def setUp(self): """Define the test client and other test variables.""" - self.template_name = "Standard" - self.base_price = 0.0 - self.core_price = 5.0 - self.memory_price = 2.0 - self.disk_size_price = 0.6 - - self.cores = 1 - self.memory = 1 - self.disk_size = 10.0 - self.manager = OpenNebulaManager(email=None, password=None, create_user=False) - self.opennebula_id = self.manager.create_template(name=self.template_name, - cores=self.cores, - memory=self.memory, - disk_size=self.disk_size) - - self.template = VirtualMachineTemplate(opennebula_id=self.opennebula_id, - base_price=self.base_price, - memory_price=self.memory_price, - core_price=self.core_price, - disk_size_price=self.disk_size_price) - self.template_id = self.template.opennebula_id() - self.opennebula_id = self.manager.create_virtualmachine(template_id=self.template_id) + self.manager = OpenNebulaManager(email=None, password=None) - self.virtualmachine = VirtualMachine(opennebula_id=self.opennebula_id, - template=self.template) def test_serializer_strips_of_public(self): - """ Test the serialized object contains no 'public-'.""" + """ Test the serialized virtual machine object contains no 'public-'.""" - template = self.manager.get_templates().first() - serialized = VirtualMachineTemplateSerializer(template) - self.assertEqual(serialized.data.name, template.name.strip('public-')) - - - - def test_model_can_create_a_virtualmachine(self): - """Test the virtualmachine model can create a virtualmachine.""" - old_count = VirtualMachine.objects.count() - self.virtualmachine.save() - new_count = VirtualMachine.objects.count() - self.assertNotEqual(old_count, new_count) + for vm in self.manager.get_vms(): + serialized = VirtualMachineSerializer(vm) + self.assertEqual(serialized.data.get('name'), vm.name.strip('public-')) + break From ef0589f691654cbbb29ffb359fdd286dfc8257fe Mon Sep 17 00:00:00 2001 From: modulos Date: Thu, 1 Jun 2017 23:06:29 +0200 Subject: [PATCH 06/10] Add german translation --- hosting/forms.py | 13 --- hosting/locale/de/LC_MESSAGES/django.po | 101 +++++++++++++----------- 2 files changed, 53 insertions(+), 61 deletions(-) diff --git a/hosting/forms.py b/hosting/forms.py index d309c983..1c7f7e88 100644 --- a/hosting/forms.py +++ b/hosting/forms.py @@ -68,8 +68,6 @@ class UserHostingKeyForm(forms.ModelForm): 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 self.data.get('name') @@ -92,14 +90,3 @@ class UserHostingKeyForm(forms.ModelForm): class Meta: model = UserHostingKey fields = ['user', 'name', 'public_key'] - labels = { - 'public_key': _('Writer'), - } - help_texts = { - 'public_key': 'Put your shit here', - } - error_messages = { - 'name': { - 'max_length': _("This writer's name is too long."), - }, - } diff --git a/hosting/locale/de/LC_MESSAGES/django.po b/hosting/locale/de/LC_MESSAGES/django.po index f40ad38c..fbf50c05 100644 --- a/hosting/locale/de/LC_MESSAGES/django.po +++ b/hosting/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-05-26 13:35+0000\n" +"POT-Creation-Date: 2017-06-01 21:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,61 +18,64 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: hosting/templates/hosting/base_short.html:67 +#: hosting/forms.py:63 +msgid "Paste here your public key" +msgstr "Fügen Sie Ihren public key ein" + +#: hosting/templates/hosting/base_short.html:68 +#: hosting/templates/hosting/base_short.html:139 msgid "My Virtual Machines" msgstr "" -#: hosting/templates/hosting/base_short.html:72 +#: hosting/templates/hosting/base_short.html:73 +#: hosting/templates/hosting/base_short.html:145 #: hosting/templates/hosting/orders.html:12 msgid "My Orders" msgstr "" -#: hosting/templates/hosting/base_short.html:77 +#: hosting/templates/hosting/base_short.html:78 +#: hosting/templates/hosting/base_short.html:152 msgid "Keys" msgstr "" -#: hosting/templates/hosting/base_short.html:82 +#: hosting/templates/hosting/base_short.html:83 +#: hosting/templates/hosting/base_short.html:158 msgid "Notifications " msgstr "" -#: hosting/templates/hosting/base_short.html:89 +#: hosting/templates/hosting/base_short.html:90 msgid "Logout" msgstr "" -#: hosting/templates/hosting/base_short.html:94 -#: hosting/templates/hosting/base_short.html:136 +#: hosting/templates/hosting/base_short.html:95 msgid "How it works" msgstr "" -#: hosting/templates/hosting/base_short.html:97 -#: hosting/templates/hosting/base_short.html:139 +#: hosting/templates/hosting/base_short.html:98 msgid "Your infrastructure" msgstr "" -#: hosting/templates/hosting/base_short.html:100 -#: hosting/templates/hosting/base_short.html:142 +#: hosting/templates/hosting/base_short.html:101 msgid "Our inftrastructure" msgstr "" -#: hosting/templates/hosting/base_short.html:103 -#: hosting/templates/hosting/base_short.html:145 +#: hosting/templates/hosting/base_short.html:104 msgid "Pricing" msgstr "" -#: hosting/templates/hosting/base_short.html:106 -#: hosting/templates/hosting/base_short.html:149 +#: hosting/templates/hosting/base_short.html:107 msgid "Contact" msgstr "" -#: hosting/templates/hosting/base_short.html:109 -#: hosting/templates/hosting/login.html:29 -#: hosting/templates/hosting/login.html:38 -#: hosting/templates/hosting/reset_password.html:24 -#: hosting/templates/hosting/signup.html:23 +#: hosting/templates/hosting/base_short.html:110 +#: hosting/templates/hosting/login.html:32 +#: hosting/templates/hosting/login.html:41 +#: hosting/templates/hosting/reset_password.html:31 +#: hosting/templates/hosting/signup.html:30 msgid "Login" msgstr "" -#: hosting/templates/hosting/base_short.html:132 +#: hosting/templates/hosting/base_short.html:134 msgid "Home" msgstr "" @@ -144,7 +147,7 @@ msgid "Customers" msgstr "" #: hosting/templates/hosting/bills.html:16 -#: hosting/templates/hosting/virtual_machine_key.html:45 +#: hosting/templates/hosting/virtual_machine_key.html:42 msgid "Name" msgstr "" @@ -173,13 +176,13 @@ msgid "Set your new password" msgstr "" #: hosting/templates/hosting/confirm_reset_password.html:28 -#: hosting/templates/hosting/reset_password.html:20 +#: hosting/templates/hosting/reset_password.html:22 msgid "Reset" msgstr "" #: hosting/templates/hosting/confirm_reset_password.html:32 -#: hosting/templates/hosting/reset_password.html:24 -#: hosting/templates/hosting/signup.html:23 +#: hosting/templates/hosting/reset_password.html:28 +#: hosting/templates/hosting/signup.html:27 msgid "Already have an account ?" msgstr "" @@ -219,21 +222,27 @@ msgstr "" msgid "The %(site_name)s team" msgstr "" -#: hosting/templates/hosting/login.html:22 +#: hosting/templates/hosting/login.html:10 +#: hosting/templates/hosting/reset_password.html:10 +#: hosting/templates/hosting/signup.html:9 +msgid "Your VM hosted in Switzerland" +msgstr "" + +#: hosting/templates/hosting/login.html:26 msgid "You haven been logged out" msgstr "" -#: hosting/templates/hosting/login.html:44 +#: hosting/templates/hosting/login.html:49 msgid "Don't have an account yet ? " msgstr "" -#: hosting/templates/hosting/login.html:44 -#: hosting/templates/hosting/signup.html:10 -#: hosting/templates/hosting/signup.html:19 +#: hosting/templates/hosting/login.html:52 +#: hosting/templates/hosting/signup.html:13 +#: hosting/templates/hosting/signup.html:21 msgid "Sign up" msgstr "" -#: hosting/templates/hosting/login.html:46 +#: hosting/templates/hosting/login.html:54 msgid "Forgot your password ? " msgstr "" @@ -310,7 +319,7 @@ msgstr "" #: hosting/templates/hosting/orders.html:19 #: hosting/templates/hosting/virtual_machine_detail.html:30 -#: hosting/templates/hosting/virtual_machine_key.html:47 +#: hosting/templates/hosting/virtual_machine_key.html:44 #: hosting/templates/hosting/virtual_machines.html:31 msgid "Status" msgstr "" @@ -344,7 +353,7 @@ msgstr "" msgid "Delete" msgstr "" -#: hosting/templates/hosting/reset_password.html:11 +#: hosting/templates/hosting/reset_password.html:14 msgid "Reset your password" msgstr "" @@ -400,50 +409,46 @@ msgstr "" msgid "Access Key" msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:22 +#: hosting/templates/hosting/virtual_machine_key.html:25 msgid "Upload your own key. " msgstr "" #: hosting/templates/hosting/virtual_machine_key.html:29 -msgid "Upload Key" -msgstr "" - -#: hosting/templates/hosting/virtual_machine_key.html:33 msgid "Or generate a new key pair." msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:37 +#: hosting/templates/hosting/virtual_machine_key.html:31 msgid "Generate Key Pair" msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:46 +#: hosting/templates/hosting/virtual_machine_key.html:43 msgid "Created at" msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:68 -#: hosting/templates/hosting/virtual_machine_key.html:81 +#: hosting/templates/hosting/virtual_machine_key.html:66 +#: hosting/templates/hosting/virtual_machine_key.html:79 msgid "Warning!" msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:68 +#: hosting/templates/hosting/virtual_machine_key.html:66 msgid "You can download your SSH private key once. Don't lost your key" msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:76 +#: hosting/templates/hosting/virtual_machine_key.html:74 msgid "Copy to Clipboard" msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:77 +#: hosting/templates/hosting/virtual_machine_key.html:75 msgid "Download" msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:81 +#: hosting/templates/hosting/virtual_machine_key.html:79 msgid "" "Your SSH private key was already generated and downloaded, if you lost it, " "contact us. " msgstr "" -#: hosting/templates/hosting/virtual_machine_key.html:84 +#: hosting/templates/hosting/virtual_machine_key.html:82 msgid "Generate my key" msgstr "" From 715d092b96d64588e80472fbb6b14944dfd5ec7d Mon Sep 17 00:00:00 2001 From: modulos Date: Fri, 2 Jun 2017 00:49:17 +0200 Subject: [PATCH 07/10] Add ssh key to new vm Create_vm now stes to public key correctly --- hosting/views.py | 43 +++++++++++------------------------ opennebula_api/models.py | 30 ++++++++---------------- opennebula_api/serializers.py | 3 ++- 3 files changed, 24 insertions(+), 52 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index a694373a..3044590b 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -355,17 +355,6 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, FormView): return render(self.request, self.template_name, context) def post(self, request, *args, **kwargs): - - # try: - # UserHostingKey.objects.get( - # user=self.request.user - # ) - # return HttpResponseRedirect(reverse('hosting:key_pair')) - - # except UserHostingKey.DoesNotExist: - # pass - - form = self.get_form() if form.is_valid(): return self.form_valid(form) @@ -418,11 +407,7 @@ class PaymentVMView(LoginRequiredMixin, FormView): return context def get(self, request, *args, **kwargs): - try: - UserHostingKey.objects.get( - user=self.request.user - ) - except UserHostingKey.DoesNotExist: + if not UserHostingKey.objects.filter( user=self.request.user).exists(): messages.success( request, 'In order to create a VM, you create/upload your SSH KEY first.' @@ -484,14 +469,16 @@ class PaymentVMView(LoginRequiredMixin, FormView): manager = OpenNebulaManager(email=owner.email, password=owner.password) # Get user ssh key - try: - user_key = UserHostingKey.objects.get( - user=self.request.user - ) - - except UserHostingKey.DoesNotExist: - pass - + if not UserHostingKey.objects.filter( user=self.request.user).exists(): + context.update({ + 'sshError': 'error', + 'form': form + }) + return render(request, self.template_name, context) + # For now just get first one + user_key = UserHostingKey.objects.filter( + user=self.request.user).first() + # Create a vm using logged user vm_id = manager.create_vm( template_id=vm_template_id, @@ -636,11 +623,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View): def get(self, request, *args, **kwargs): - try: - UserHostingKey.objects.get( - user=self.request.user - ) - except UserHostingKey.DoesNotExist: + if not UserHostingKey.objects.filter( user=self.request.user).exists(): messages.success( request, 'In order to create a VM, you need to create/upload your SSH KEY first.' @@ -664,7 +647,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View): ) context = { 'error': 'connection' - } + } return render(request, self.template_name, context) diff --git a/opennebula_api/models.py b/opennebula_api/models.py index 4fa5d011..5d93c1bd 100644 --- a/opennebula_api/models.py +++ b/opennebula_api/models.py @@ -260,7 +260,6 @@ class OpenNebulaManager(): vd {image_id} - """.format(size=1024 * int(specs['disk_size']), image_id=image_id) @@ -282,10 +281,18 @@ class OpenNebulaManager(): {image} {image_uname} - """.format(size=1024 * int(specs['disk_size']), image=image, image_uname=image_uname) + + + if ssh_key: + vm_specs += """ + {ssh} + YES + + + """.format(ssh=public_key) vm_id = self.client.call(oca.VmTemplate.METHODS['instantiate'], template.id, '', @@ -293,25 +300,6 @@ class OpenNebulaManager(): vm_specs, False) - self.oneadmin_client.call( - 'vm.update', - vm_id, - """ - {ssh} - - """.format(ssh=ssh_key) - ) - try: - self.oneadmin_client.call( - oca.VirtualMachine.METHODS['chown'], - vm_id, - self.opennebula_user.id, - self.opennebula_user.group_ids[0] - ) - except AttributeError: - logger.info( - 'Could not change owner for vm with id: {}.'.format(vm_id)) - self.oneadmin_client.call( oca.VirtualMachine.METHODS['action'], 'release', diff --git a/opennebula_api/serializers.py b/opennebula_api/serializers.py index 226d9f47..824ae7c6 100644 --- a/opennebula_api/serializers.py +++ b/opennebula_api/serializers.py @@ -15,7 +15,6 @@ class VirtualMachineTemplateSerializer(serializers.Serializer): cores = serializers.SerializerMethodField() disk_size = serializers.SerializerMethodField() memory = serializers.SerializerMethodField() - price = serializers.SerializerMethodField() def get_cores(self, obj): if hasattr(obj.template, 'vcpu'): @@ -39,6 +38,8 @@ class VirtualMachineTemplateSerializer(serializers.Serializer): def get_name(self, obj): return obj.name.strip('public-') + + class VirtualMachineSerializer(serializers.Serializer): """Serializer to map the virtual machine instance into JSON format.""" From e4291083bd6cb580f8479b2a5b05effcdd37efe7 Mon Sep 17 00:00:00 2001 From: modulos Date: Fri, 2 Jun 2017 00:58:48 +0200 Subject: [PATCH 08/10] Append changes --- Changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changelog b/Changelog index 7df1f113..ae899654 100644 --- a/Changelog +++ b/Changelog @@ -5,3 +5,8 @@ * [datacenterlight] Fix initially shown price 1.0.2: 2017-05-28 * [datacenterlight] Fixed login redirecting to blank page after logout + +next + * [opennebula_api] Improve testing, add ssh key functions + * [opennebula_api] Remove template views + * [datacenterlight] Allow user to have multiple ssh keys From 83705984d069c215fb139d039e6442653d0bec94 Mon Sep 17 00:00:00 2001 From: Levi Date: Fri, 2 Jun 2017 10:36:17 -0500 Subject: [PATCH 09/10] removed more info button --- datacenterlight/templates/datacenterlight/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/datacenterlight/templates/datacenterlight/index.html b/datacenterlight/templates/datacenterlight/index.html index 89297926..f3ea045d 100755 --- a/datacenterlight/templates/datacenterlight/index.html +++ b/datacenterlight/templates/datacenterlight/index.html @@ -217,7 +217,6 @@

    {% trans "We are cutting down the costs significantly!" %}

    {% trans "Affordable VM hosting based in Switzerland" %}

    - {% trans "More Info" %}
    From cd9c8938ed2ccb63b3c03dedc52dfd7cc67702bf Mon Sep 17 00:00:00 2001 From: Levi Date: Fri, 2 Jun 2017 11:11:04 -0500 Subject: [PATCH 10/10] hidden footbar on mobile devices --- Changelog | 2 ++ hosting/templates/hosting/base_short.html | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 7df1f113..a309e059 100644 --- a/Changelog +++ b/Changelog @@ -5,3 +5,5 @@ * [datacenterlight] Fix initially shown price 1.0.2: 2017-05-28 * [datacenterlight] Fixed login redirecting to blank page after logout +1.0.3: 2017-06-02 + * [datacenterlight] Hotfix, remove footer on mobile devices diff --git a/hosting/templates/hosting/base_short.html b/hosting/templates/hosting/base_short.html index c6d1772e..3feda88a 100644 --- a/hosting/templates/hosting/base_short.html +++ b/hosting/templates/hosting/base_short.html @@ -126,7 +126,7 @@