Merge branch 'task/5509/add-keys-to-opennebula-user' into 'master'
Save user's key in opennebula See merge request ungleich-public/dynamicweb!704
This commit is contained in:
		
				commit
				
					
						59a78dd8bb
					
				
			
		
					 10 changed files with 195 additions and 94 deletions
				
			
		| 
						 | 
					@ -186,3 +186,8 @@ footer .dcl-link-separator::before {
 | 
				
			||||||
  background: transparent !important;
 | 
					  background: transparent !important;
 | 
				
			||||||
  resize: none;
 | 
					  resize: none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.existing-keys-title {
 | 
				
			||||||
 | 
					  font-weight: bold;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,6 @@ from django.core.mail import EmailMessage
 | 
				
			||||||
from django.core.urlresolvers import reverse
 | 
					from django.core.urlresolvers import reverse
 | 
				
			||||||
from django.utils import translation
 | 
					from django.utils import translation
 | 
				
			||||||
from django.utils.translation import ugettext_lazy as _
 | 
					from django.utils.translation import ugettext_lazy as _
 | 
				
			||||||
from time import sleep
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dynamicweb.celery import app
 | 
					from dynamicweb.celery import app
 | 
				
			||||||
from hosting.models import HostingOrder
 | 
					from hosting.models import HostingOrder
 | 
				
			||||||
| 
						 | 
					@ -16,7 +15,7 @@ from membership.models import CustomUser
 | 
				
			||||||
from opennebula_api.models import OpenNebulaManager
 | 
					from opennebula_api.models import OpenNebulaManager
 | 
				
			||||||
from opennebula_api.serializers import VirtualMachineSerializer
 | 
					from opennebula_api.serializers import VirtualMachineSerializer
 | 
				
			||||||
from utils.hosting_utils import (
 | 
					from utils.hosting_utils import (
 | 
				
			||||||
    get_all_public_keys, get_or_create_vm_detail, ping_ok
 | 
					    get_all_public_keys, get_or_create_vm_detail
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from utils.mailer import BaseEmail
 | 
					from utils.mailer import BaseEmail
 | 
				
			||||||
from utils.stripe_utils import StripeUtils
 | 
					from utils.stripe_utils import StripeUtils
 | 
				
			||||||
| 
						 | 
					@ -79,10 +78,14 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id):
 | 
				
			||||||
        # Create OpenNebulaManager
 | 
					        # Create OpenNebulaManager
 | 
				
			||||||
        manager = OpenNebulaManager(email=on_user, password=on_pass)
 | 
					        manager = OpenNebulaManager(email=on_user, password=on_pass)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        custom_user = CustomUser.objects.get(email=user.get('email'))
 | 
				
			||||||
 | 
					        pub_keys = get_all_public_keys(custom_user)
 | 
				
			||||||
 | 
					        if manager.email != settings.OPENNEBULA_USERNAME:
 | 
				
			||||||
 | 
					            manager.save_key_in_opennebula_user('\n'.join(pub_keys))
 | 
				
			||||||
        vm_id = manager.create_vm(
 | 
					        vm_id = manager.create_vm(
 | 
				
			||||||
            template_id=vm_template_id,
 | 
					            template_id=vm_template_id,
 | 
				
			||||||
            specs=specs,
 | 
					            specs=specs,
 | 
				
			||||||
            ssh_key=settings.ONEADMIN_USER_SSH_PUBLIC_KEY,
 | 
					            ssh_key='\n'.join(pub_keys),
 | 
				
			||||||
            vm_name=vm_name
 | 
					            vm_name=vm_name
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -188,65 +191,9 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id):
 | 
				
			||||||
            email = BaseEmail(**email_data)
 | 
					            email = BaseEmail(**email_data)
 | 
				
			||||||
            email.send()
 | 
					            email.send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # try to see if we have the IPv6 of the new vm and that if the ssh
 | 
					 | 
				
			||||||
            # keys can be configured
 | 
					 | 
				
			||||||
            vm_ipv6 = manager.get_ipv6(vm_id)
 | 
					 | 
				
			||||||
            logger.debug("New VM ID is {vm_id}".format(vm_id=vm_id))
 | 
					            logger.debug("New VM ID is {vm_id}".format(vm_id=vm_id))
 | 
				
			||||||
            if vm_ipv6 is not None:
 | 
					            if vm_id > 0:
 | 
				
			||||||
                custom_user = CustomUser.objects.get(email=user.get('email'))
 | 
					 | 
				
			||||||
                get_or_create_vm_detail(custom_user, manager, vm_id)
 | 
					                get_or_create_vm_detail(custom_user, manager, vm_id)
 | 
				
			||||||
                if custom_user is not None:
 | 
					 | 
				
			||||||
                    public_keys = get_all_public_keys(custom_user)
 | 
					 | 
				
			||||||
                    keys = [{'value': key, 'state': True} for key in
 | 
					 | 
				
			||||||
                            public_keys]
 | 
					 | 
				
			||||||
                    if len(keys) > 0:
 | 
					 | 
				
			||||||
                        logger.debug(
 | 
					 | 
				
			||||||
                            "Calling configure on {host} for "
 | 
					 | 
				
			||||||
                            "{num_keys} keys".format(
 | 
					 | 
				
			||||||
                                host=vm_ipv6, num_keys=len(keys)
 | 
					 | 
				
			||||||
                            )
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                        # Let's wait until the IP responds to ping before we
 | 
					 | 
				
			||||||
                        # run the cdist configure on the host
 | 
					 | 
				
			||||||
                        did_manage_public_key = False
 | 
					 | 
				
			||||||
                        for i in range(0, 15):
 | 
					 | 
				
			||||||
                            if ping_ok(vm_ipv6):
 | 
					 | 
				
			||||||
                                logger.debug(
 | 
					 | 
				
			||||||
                                    "{} is pingable. Doing a "
 | 
					 | 
				
			||||||
                                    "manage_public_key".format(vm_ipv6)
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                                sleep(10)
 | 
					 | 
				
			||||||
                                manager.manage_public_key(
 | 
					 | 
				
			||||||
                                    keys, hosts=[vm_ipv6]
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                                did_manage_public_key = True
 | 
					 | 
				
			||||||
                                break
 | 
					 | 
				
			||||||
                            else:
 | 
					 | 
				
			||||||
                                logger.debug(
 | 
					 | 
				
			||||||
                                    "Can't ping {}. Wait 5 secs".format(
 | 
					 | 
				
			||||||
                                        vm_ipv6
 | 
					 | 
				
			||||||
                                    )
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                                sleep(5)
 | 
					 | 
				
			||||||
                        if not did_manage_public_key:
 | 
					 | 
				
			||||||
                            emsg = ("Waited for over 75 seconds for {} to be "
 | 
					 | 
				
			||||||
                                    "pingable. But the VM was not reachable. "
 | 
					 | 
				
			||||||
                                    "So, gave up manage_public_key. Please do "
 | 
					 | 
				
			||||||
                                    "this manually".format(vm_ipv6))
 | 
					 | 
				
			||||||
                            logger.error(emsg)
 | 
					 | 
				
			||||||
                            email_data = {
 | 
					 | 
				
			||||||
                                'subject': '{} CELERY TASK INCOMPLETE: {} not '
 | 
					 | 
				
			||||||
                                           'pingable for 75 seconds'.format(
 | 
					 | 
				
			||||||
                                                settings.DCL_TEXT, vm_ipv6
 | 
					 | 
				
			||||||
                                            ),
 | 
					 | 
				
			||||||
                                'from_email': current_task.request.hostname,
 | 
					 | 
				
			||||||
                                'to': settings.DCL_ERROR_EMAILS_TO_LIST,
 | 
					 | 
				
			||||||
                                'body': emsg
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            email = EmailMessage(**email_data)
 | 
					 | 
				
			||||||
                            email.send()
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                logger.debug("VM's ipv6 is None. Hence not created VMDetail")
 | 
					 | 
				
			||||||
    except Exception as e:
 | 
					    except Exception as e:
 | 
				
			||||||
        logger.error(str(e))
 | 
					        logger.error(str(e))
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,6 +134,38 @@
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <form id="virtual_machine_create_form" action="" method="POST">
 | 
					        <form id="virtual_machine_create_form" action="" method="POST">
 | 
				
			||||||
            {% csrf_token %}
 | 
					            {% csrf_token %}
 | 
				
			||||||
 | 
					            {% if generic_payment_details %}
 | 
				
			||||||
 | 
					            {% else %}
 | 
				
			||||||
 | 
					                {% comment %}
 | 
				
			||||||
 | 
					                We are in VM buy flow and we want user to click the "Place order" button.
 | 
				
			||||||
 | 
					                At this point, we also want the user to input the SSH key for the VM.
 | 
				
			||||||
 | 
					                {% endcomment %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                {% if messages %}
 | 
				
			||||||
 | 
					                    <div class="alert alert-warning">
 | 
				
			||||||
 | 
					                        {% for message in messages %}
 | 
				
			||||||
 | 
					                        <span>{{ message }}</span>
 | 
				
			||||||
 | 
					                        {% endfor %}
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                {% endif %}
 | 
				
			||||||
 | 
					                <div class="dashboard-container-head">
 | 
				
			||||||
 | 
					                    <h2 class="dashboard-title-thin"><i class="fa fa-key" aria-hidden="true"></i> {% trans "Add your public SSH key" %}</h2>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            <div class="existing-keys">
 | 
				
			||||||
 | 
					                {% if keys|length > 0 %}
 | 
				
			||||||
 | 
					                <div class="existing-keys-title">Existing keys</div>
 | 
				
			||||||
 | 
					                {% endif %}
 | 
				
			||||||
 | 
					                {% for key in keys %}
 | 
				
			||||||
 | 
					                <textarea class="form-control input-no-border" style="width: 100%" readonly  rows="6">
 | 
				
			||||||
 | 
					                    {{key}}
 | 
				
			||||||
 | 
					                </textarea>
 | 
				
			||||||
 | 
					                    <br/>
 | 
				
			||||||
 | 
					                {% endfor %}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					                {% for field in form %}
 | 
				
			||||||
 | 
					                    {% bootstrap_field field %}
 | 
				
			||||||
 | 
					                {% endfor %}
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
            <div class="row">
 | 
					            <div class="row">
 | 
				
			||||||
                <div class="col-sm-8">
 | 
					                <div class="col-sm-8">
 | 
				
			||||||
                    {% if generic_payment_details %}
 | 
					                    {% if generic_payment_details %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,8 @@ from django.views.decorators.cache import cache_control
 | 
				
			||||||
from django.views.generic import FormView, CreateView, DetailView
 | 
					from django.views.generic import FormView, CreateView, DetailView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from hosting.forms import (
 | 
					from hosting.forms import (
 | 
				
			||||||
    HostingUserLoginForm, GenericPaymentForm, ProductPaymentForm
 | 
					    HostingUserLoginForm, GenericPaymentForm, ProductPaymentForm,
 | 
				
			||||||
 | 
					    UserHostingKeyForm
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from hosting.models import (
 | 
					from hosting.models import (
 | 
				
			||||||
    HostingBill, HostingOrder, UserCardDetail, GenericProduct
 | 
					    HostingBill, HostingOrder, UserCardDetail, GenericProduct
 | 
				
			||||||
| 
						 | 
					@ -24,7 +25,7 @@ from utils.forms import (
 | 
				
			||||||
    BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm,
 | 
					    BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm,
 | 
				
			||||||
    BillingAddress
 | 
					    BillingAddress
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from utils.hosting_utils import get_vm_price_with_vat
 | 
					from utils.hosting_utils import get_vm_price_with_vat, get_all_public_keys
 | 
				
			||||||
from utils.stripe_utils import StripeUtils
 | 
					from utils.stripe_utils import StripeUtils
 | 
				
			||||||
from utils.tasks import send_plain_email_task
 | 
					from utils.tasks import send_plain_email_task
 | 
				
			||||||
from .cms_models import DCLCalculatorPluginModel
 | 
					from .cms_models import DCLCalculatorPluginModel
 | 
				
			||||||
| 
						 | 
					@ -529,12 +530,18 @@ class PaymentOrderView(FormView):
 | 
				
			||||||
            return self.render_to_response(context)
 | 
					            return self.render_to_response(context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OrderConfirmationView(DetailView):
 | 
					class OrderConfirmationView(DetailView, FormView):
 | 
				
			||||||
 | 
					    form_class = UserHostingKeyForm
 | 
				
			||||||
    template_name = "datacenterlight/order_detail.html"
 | 
					    template_name = "datacenterlight/order_detail.html"
 | 
				
			||||||
    payment_template_name = 'datacenterlight/landing_payment.html'
 | 
					    payment_template_name = 'datacenterlight/landing_payment.html'
 | 
				
			||||||
    context_object_name = "order"
 | 
					    context_object_name = "order"
 | 
				
			||||||
    model = HostingOrder
 | 
					    model = HostingOrder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_form_kwargs(self):
 | 
				
			||||||
 | 
					        kwargs = super(OrderConfirmationView, self).get_form_kwargs()
 | 
				
			||||||
 | 
					        kwargs.update({'request': self.request})
 | 
				
			||||||
 | 
					        return kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @cache_control(no_cache=True, must_revalidate=True, no_store=True)
 | 
					    @cache_control(no_cache=True, must_revalidate=True, no_store=True)
 | 
				
			||||||
    def get(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        context = {}
 | 
					        context = {}
 | 
				
			||||||
| 
						 | 
					@ -567,6 +574,8 @@ class OrderConfirmationView(DetailView):
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            context.update({
 | 
					            context.update({
 | 
				
			||||||
                'vm': request.session.get('specs'),
 | 
					                'vm': request.session.get('specs'),
 | 
				
			||||||
 | 
					                'form': UserHostingKeyForm(request=self.request),
 | 
				
			||||||
 | 
					                'keys': get_all_public_keys(self.request.user)
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        context.update({
 | 
					        context.update({
 | 
				
			||||||
            'site_url': reverse('datacenterlight:index'),
 | 
					            'site_url': reverse('datacenterlight:index'),
 | 
				
			||||||
| 
						 | 
					@ -579,6 +588,31 @@ class OrderConfirmationView(DetailView):
 | 
				
			||||||
        return render(request, self.template_name, context)
 | 
					        return render(request, self.template_name, context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post(self, request, *args, **kwargs):
 | 
					    def post(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        # Check ssh public key and then proceed
 | 
				
			||||||
 | 
					        form = self.get_form()
 | 
				
			||||||
 | 
					        required = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # SSH key validation is required only if the user doesn't have an
 | 
				
			||||||
 | 
					        # existing key and user has input some value in the add ssh key fields
 | 
				
			||||||
 | 
					        if (len(get_all_public_keys(self.request.user)) > 0 and
 | 
				
			||||||
 | 
					                (len(form.data.get('public_key')) == 0 and
 | 
				
			||||||
 | 
					                         len(form.data.get('name')) == 0)):
 | 
				
			||||||
 | 
					            required = False
 | 
				
			||||||
 | 
					        form.fields['name'].required = required
 | 
				
			||||||
 | 
					        form.fields['public_key'].required = required
 | 
				
			||||||
 | 
					        if not form.is_valid():
 | 
				
			||||||
 | 
					            response = {
 | 
				
			||||||
 | 
					                'status': False,
 | 
				
			||||||
 | 
					                'msg_title': str(_('SSH key related error occurred')),
 | 
				
			||||||
 | 
					                'msg_body': "<br/>".join([str(v) for k,v in form.errors.items()]),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return JsonResponse(response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if required:
 | 
				
			||||||
 | 
					            # We have a valid SSH key from the user, save it in opennebula and
 | 
				
			||||||
 | 
					            # db and proceed further
 | 
				
			||||||
 | 
					            form.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        user = request.session.get('user')
 | 
					        user = request.session.get('user')
 | 
				
			||||||
        stripe_api_cus_id = request.session.get('customer')
 | 
					        stripe_api_cus_id = request.session.get('customer')
 | 
				
			||||||
        stripe_utils = StripeUtils()
 | 
					        stripe_utils = StripeUtils()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					 | 
				
			||||||
import tempfile
 | 
					import tempfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.contrib.auth import authenticate
 | 
					from django.contrib.auth import authenticate
 | 
				
			||||||
| 
						 | 
					@ -187,7 +187,8 @@ class UserHostingKeyForm(forms.ModelForm):
 | 
				
			||||||
        alerts the user of it.
 | 
					        alerts the user of it.
 | 
				
			||||||
        :return:
 | 
					        :return:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if 'generate' in self.request.POST:
 | 
					        if ('generate' in self.request.POST
 | 
				
			||||||
 | 
					                or not self.fields['public_key'].required):
 | 
				
			||||||
            return self.data.get('public_key')
 | 
					            return self.data.get('public_key')
 | 
				
			||||||
        KEY_ERROR_MESSAGE = _("Please input a proper SSH key")
 | 
					        KEY_ERROR_MESSAGE = _("Please input a proper SSH key")
 | 
				
			||||||
        openssh_pubkey_str = self.data.get('public_key').strip()
 | 
					        openssh_pubkey_str = self.data.get('public_key').strip()
 | 
				
			||||||
| 
						 | 
					@ -214,6 +215,10 @@ class UserHostingKeyForm(forms.ModelForm):
 | 
				
			||||||
        return openssh_pubkey_str
 | 
					        return openssh_pubkey_str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def clean_name(self):
 | 
					    def clean_name(self):
 | 
				
			||||||
 | 
					        INVALID_NAME_MESSAGE = _("Comma not accepted in the name of the key")
 | 
				
			||||||
 | 
					        if "," in self.data.get('name'):
 | 
				
			||||||
 | 
					            logger.debug(INVALID_NAME_MESSAGE)
 | 
				
			||||||
 | 
					            raise forms.ValidationError(INVALID_NAME_MESSAGE)
 | 
				
			||||||
        return self.data.get('name')
 | 
					        return self.data.get('name')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def clean_user(self):
 | 
					    def clean_user(self):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -109,8 +109,11 @@ $(document).ready(function() {
 | 
				
			||||||
                modal_btn = $('#createvm-modal-done-btn');
 | 
					                modal_btn = $('#createvm-modal-done-btn');
 | 
				
			||||||
                $('#createvm-modal-title').text(data.msg_title);
 | 
					                $('#createvm-modal-title').text(data.msg_title);
 | 
				
			||||||
                $('#createvm-modal-body').html(data.msg_body);
 | 
					                $('#createvm-modal-body').html(data.msg_body);
 | 
				
			||||||
                modal_btn.attr('href', data.redirect)
 | 
					                if (data.redirect) {
 | 
				
			||||||
                    .removeClass('hide');
 | 
					                    modal_btn.attr('href', data.redirect).removeClass('hide');
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    modal_btn.attr('href', "");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                if (data.status === true) {
 | 
					                if (data.status === true) {
 | 
				
			||||||
                    fa_icon.attr('class', 'checkmark');
 | 
					                    fa_icon.attr('class', 'checkmark');
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -198,6 +198,35 @@
 | 
				
			||||||
            {% block submit_btn %}
 | 
					            {% block submit_btn %}
 | 
				
			||||||
                <form method="post" id="virtual_machine_create_form">
 | 
					                <form method="post" id="virtual_machine_create_form">
 | 
				
			||||||
                    {% csrf_token %}
 | 
					                    {% csrf_token %}
 | 
				
			||||||
 | 
					                    {% comment %}
 | 
				
			||||||
 | 
					                    We are in VM buy flow and we want user to click the "Place order" button.
 | 
				
			||||||
 | 
					                    At this point, we also want the user to input the SSH key for the VM.
 | 
				
			||||||
 | 
					                    {% endcomment %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    {% if messages %}
 | 
				
			||||||
 | 
					                        <div class="alert alert-warning">
 | 
				
			||||||
 | 
					                            {% for message in messages %}
 | 
				
			||||||
 | 
					                            <span>{{ message }}</span>
 | 
				
			||||||
 | 
					                            {% endfor %}
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    {% endif %}
 | 
				
			||||||
 | 
					                    <div class="dashboard-container-head">
 | 
				
			||||||
 | 
					                        <h2 class="dashboard-title-thin"><i class="fa fa-key" aria-hidden="true"></i> {% trans "Add your public SSH key" %}</h2>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                <div class="existing-keys">
 | 
				
			||||||
 | 
					                    {% if keys|length > 0 %}
 | 
				
			||||||
 | 
					                    <div class="existing-keys-title">Existing keys</div>
 | 
				
			||||||
 | 
					                    {% endif %}
 | 
				
			||||||
 | 
					                    {% for key in keys %}
 | 
				
			||||||
 | 
					                    <textarea class="form-control input-no-border" style="width: 100%" readonly  rows="6">
 | 
				
			||||||
 | 
					                        {{key}}
 | 
				
			||||||
 | 
					                    </textarea>
 | 
				
			||||||
 | 
					                        <br/>
 | 
				
			||||||
 | 
					                    {% endfor %}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                    {% for field in form %}
 | 
				
			||||||
 | 
					                        {% bootstrap_field field %}
 | 
				
			||||||
 | 
					                    {% endfor %}
 | 
				
			||||||
                    <div class="row">
 | 
					                    <div class="row">
 | 
				
			||||||
                        <div class="col-sm-8">
 | 
					                        <div class="col-sm-8">
 | 
				
			||||||
                            <div class="dcl-place-order-text">{% blocktrans with vm_price=vm.total_price|floatformat:2|intcomma %}By clicking "Place order" this plan will charge your credit card account with {{ vm_price }} CHF/month{% endblocktrans %}.</div>
 | 
					                            <div class="dcl-place-order-text">{% blocktrans with vm_price=vm.total_price|floatformat:2|intcomma %}By clicking "Place order" this plan will charge your credit card account with {{ vm_price }} CHF/month{% endblocktrans %}.</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
from django.conf.urls import url
 | 
					from django.conf.urls import url
 | 
				
			||||||
from django.contrib.auth import views as auth_views
 | 
					from django.contrib.auth import views as auth_views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .views import (
 | 
					from .views import (
 | 
				
			||||||
    DjangoHostingView, RailsHostingView, PaymentVMView, NodeJSHostingView,
 | 
					    DjangoHostingView, RailsHostingView, PaymentVMView, NodeJSHostingView,
 | 
				
			||||||
    LoginView, SignupView, SignupValidateView, SignupValidatedView, IndexView,
 | 
					    LoginView, SignupView, SignupValidateView, SignupValidatedView, IndexView,
 | 
				
			||||||
| 
						 | 
					@ -12,7 +13,6 @@ from .views import (
 | 
				
			||||||
    InvoiceListView, InvoiceDetailView, CheckUserVM
 | 
					    InvoiceListView, InvoiceDetailView, CheckUserVM
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
urlpatterns = [
 | 
					urlpatterns = [
 | 
				
			||||||
    url(r'index/?$', IndexView.as_view(), name='index'),
 | 
					    url(r'index/?$', IndexView.as_view(), name='index'),
 | 
				
			||||||
    url(r'django/?$', DjangoHostingView.as_view(), name='djangohosting'),
 | 
					    url(r'django/?$', DjangoHostingView.as_view(), name='djangohosting'),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,6 +49,7 @@ from utils.forms import (
 | 
				
			||||||
    BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm,
 | 
					    BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm,
 | 
				
			||||||
    ResendActivationEmailForm
 | 
					    ResendActivationEmailForm
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					from utils.hosting_utils import get_all_public_keys
 | 
				
			||||||
from utils.hosting_utils import get_vm_price_with_vat, HostingUtils
 | 
					from utils.hosting_utils import get_vm_price_with_vat, HostingUtils
 | 
				
			||||||
from utils.mailer import BaseEmail
 | 
					from utils.mailer import BaseEmail
 | 
				
			||||||
from utils.stripe_utils import StripeUtils
 | 
					from utils.stripe_utils import StripeUtils
 | 
				
			||||||
| 
						 | 
					@ -466,7 +467,9 @@ class SSHKeyDeleteView(LoginRequiredMixin, DeleteView):
 | 
				
			||||||
        pk = self.kwargs.get('pk')
 | 
					        pk = self.kwargs.get('pk')
 | 
				
			||||||
        # Get user ssh key
 | 
					        # Get user ssh key
 | 
				
			||||||
        public_key = UserHostingKey.objects.get(pk=pk).public_key
 | 
					        public_key = UserHostingKey.objects.get(pk=pk).public_key
 | 
				
			||||||
        manager.manage_public_key([{'value': public_key, 'state': False}])
 | 
					        keys = UserHostingKey.objects.filter(user=self.request.user)
 | 
				
			||||||
 | 
					        keys_to_save = [k.public_key for k in keys if k.public_key != public_key]
 | 
				
			||||||
 | 
					        manager.save_key_in_opennebula_user('\n'.join(keys_to_save), update_type=0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return super(SSHKeyDeleteView, self).delete(request, *args, **kwargs)
 | 
					        return super(SSHKeyDeleteView, self).delete(request, *args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -515,8 +518,8 @@ class SSHKeyChoiceView(LoginRequiredMixin, View):
 | 
				
			||||||
            email=owner.email,
 | 
					            email=owner.email,
 | 
				
			||||||
            password=owner.password
 | 
					            password=owner.password
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        public_key_str = public_key.decode()
 | 
					        keys = get_all_public_keys(request.user)
 | 
				
			||||||
        manager.manage_public_key([{'value': public_key_str, 'state': True}])
 | 
					        manager.save_key_in_opennebula_user('\n'.join(keys))
 | 
				
			||||||
        return redirect(reverse_lazy('hosting:ssh_keys'), foo='bar')
 | 
					        return redirect(reverse_lazy('hosting:ssh_keys'), foo='bar')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -566,10 +569,8 @@ class SSHKeyCreateView(LoginRequiredMixin, FormView):
 | 
				
			||||||
            email=owner.email,
 | 
					            email=owner.email,
 | 
				
			||||||
            password=owner.password
 | 
					            password=owner.password
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        public_key = form.cleaned_data['public_key']
 | 
					        keys_to_save = get_all_public_keys(self.request.user)
 | 
				
			||||||
        if type(public_key) is bytes:
 | 
					        manager.save_key_in_opennebula_user('\n'.join(keys_to_save))
 | 
				
			||||||
            public_key = public_key.decode()
 | 
					 | 
				
			||||||
        manager.manage_public_key([{'value': public_key, 'state': True}])
 | 
					 | 
				
			||||||
        return HttpResponseRedirect(self.success_url)
 | 
					        return HttpResponseRedirect(self.success_url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post(self, request, *args, **kwargs):
 | 
					    def post(self, request, *args, **kwargs):
 | 
				
			||||||
| 
						 | 
					@ -837,13 +838,19 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
				
			||||||
            return self.form_invalid(form)
 | 
					            return self.form_invalid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
 | 
					class OrdersHostingDetailView(LoginRequiredMixin, DetailView, FormView):
 | 
				
			||||||
 | 
					    form_class = UserHostingKeyForm
 | 
				
			||||||
    template_name = "hosting/order_detail.html"
 | 
					    template_name = "hosting/order_detail.html"
 | 
				
			||||||
    context_object_name = "order"
 | 
					    context_object_name = "order"
 | 
				
			||||||
    login_url = reverse_lazy('hosting:login')
 | 
					    login_url = reverse_lazy('hosting:login')
 | 
				
			||||||
    permission_required = ['view_hostingorder']
 | 
					    permission_required = ['view_hostingorder']
 | 
				
			||||||
    model = HostingOrder
 | 
					    model = HostingOrder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_form_kwargs(self):
 | 
				
			||||||
 | 
					        kwargs = super(OrdersHostingDetailView, self).get_form_kwargs()
 | 
				
			||||||
 | 
					        kwargs.update({'request': self.request})
 | 
				
			||||||
 | 
					        return kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_object(self, queryset=None):
 | 
					    def get_object(self, queryset=None):
 | 
				
			||||||
        order_id = self.kwargs.get('pk')
 | 
					        order_id = self.kwargs.get('pk')
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
| 
						 | 
					@ -868,6 +875,8 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.request.GET.get('page') == 'payment':
 | 
					        if self.request.GET.get('page') == 'payment':
 | 
				
			||||||
            context['page_header_text'] = _('Confirm Order')
 | 
					            context['page_header_text'] = _('Confirm Order')
 | 
				
			||||||
 | 
					            context['form'] = UserHostingKeyForm(request=self.request)
 | 
				
			||||||
 | 
					            context['keys'] = get_all_public_keys(self.request.user)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            context['page_header_text'] = _('Invoice')
 | 
					            context['page_header_text'] = _('Invoice')
 | 
				
			||||||
            if not self.request.user.has_perm(
 | 
					            if not self.request.user.has_perm(
 | 
				
			||||||
| 
						 | 
					@ -993,6 +1002,31 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @method_decorator(decorators)
 | 
					    @method_decorator(decorators)
 | 
				
			||||||
    def post(self, request):
 | 
					    def post(self, request):
 | 
				
			||||||
 | 
					        # Check ssh public key and then proceed
 | 
				
			||||||
 | 
					        form = self.get_form()
 | 
				
			||||||
 | 
					        required = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # SSH key validation is required only if the user doesn't have an
 | 
				
			||||||
 | 
					        # existing key and user has input some value in the add ssh key fields
 | 
				
			||||||
 | 
					        if (len(get_all_public_keys(self.request.user)) > 0 and
 | 
				
			||||||
 | 
					                (len(form.data.get('public_key')) == 0 and
 | 
				
			||||||
 | 
					                         len(form.data.get('name')) == 0)):
 | 
				
			||||||
 | 
					            required = False
 | 
				
			||||||
 | 
					        form.fields['name'].required = required
 | 
				
			||||||
 | 
					        form.fields['public_key'].required = required
 | 
				
			||||||
 | 
					        if not form.is_valid():
 | 
				
			||||||
 | 
					            response = {
 | 
				
			||||||
 | 
					                'status': False,
 | 
				
			||||||
 | 
					                'msg_title': str(_('SSH key related error occurred')),
 | 
				
			||||||
 | 
					                'msg_body': "<br/>".join([str(v) for k,v in form.errors.items()]),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return JsonResponse(response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if required:
 | 
				
			||||||
 | 
					            # We have a valid SSH key from the user, save it in opennebula and
 | 
				
			||||||
 | 
					            # db and proceed further
 | 
				
			||||||
 | 
					            form.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        template = request.session.get('template')
 | 
					        template = request.session.get('template')
 | 
				
			||||||
        specs = request.session.get('specs')
 | 
					        specs = request.session.get('specs')
 | 
				
			||||||
        stripe_utils = StripeUtils()
 | 
					        stripe_utils = StripeUtils()
 | 
				
			||||||
| 
						 | 
					@ -1573,7 +1607,8 @@ class VirtualMachineView(LoginRequiredMixin, View):
 | 
				
			||||||
                'virtual_machine': serializer.data,
 | 
					                'virtual_machine': serializer.data,
 | 
				
			||||||
                'order': HostingOrder.objects.get(
 | 
					                'order': HostingOrder.objects.get(
 | 
				
			||||||
                    vm_id=serializer.data['vm_id']
 | 
					                    vm_id=serializer.data['vm_id']
 | 
				
			||||||
                )
 | 
					                ),
 | 
				
			||||||
 | 
					                'keys': UserHostingKey.objects.filter(user=request.user)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        except Exception as ex:
 | 
					        except Exception as ex:
 | 
				
			||||||
            logger.debug("Exception generated {}".format(str(ex)))
 | 
					            logger.debug("Exception generated {}".format(str(ex)))
 | 
				
			||||||
| 
						 | 
					@ -1639,7 +1674,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
 | 
				
			||||||
                "manager.delete_vm returned False. Hence, error making "
 | 
					                "manager.delete_vm returned False. Hence, error making "
 | 
				
			||||||
                "xml-rpc call to delete vm failed."
 | 
					                "xml-rpc call to delete vm failed."
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            response['text'] = ugettext('Error terminating VM') + vm.id
 | 
					            response['text'] = str(_('Error terminating VM')) + str(vm.id)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            for t in range(15):
 | 
					            for t in range(15):
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,22 +207,8 @@ class OpenNebulaManager():
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                vm_pool.info()
 | 
					                vm_pool.info()
 | 
				
			||||||
            return vm_pool
 | 
					            return vm_pool
 | 
				
			||||||
        except AttributeError:
 | 
					        except AttributeError as ae:
 | 
				
			||||||
            logger.error(
 | 
					            logger.error("AttributeError : %s" % str(ae))
 | 
				
			||||||
                'Could not connect via client, using oneadmin instead')
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                vm_pool = oca.VirtualMachinePool(self.oneadmin_client)
 | 
					 | 
				
			||||||
                if infoextended:
 | 
					 | 
				
			||||||
                    vm_pool.infoextended(
 | 
					 | 
				
			||||||
                        filter=-1,  # User's resources and any of his groups
 | 
					 | 
				
			||||||
                        vm_state=-1  # Look for VMs in any state, except DONE
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    vm_pool.info(filter=-2)
 | 
					 | 
				
			||||||
                return vm_pool
 | 
					 | 
				
			||||||
            except:
 | 
					 | 
				
			||||||
                raise ConnectionRefusedError
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        except ConnectionRefusedError:
 | 
					        except ConnectionRefusedError:
 | 
				
			||||||
            logger.error(
 | 
					            logger.error(
 | 
				
			||||||
                'Could not connect to host: {host} via protocol {protocol}'.format(
 | 
					                'Could not connect to host: {host} via protocol {protocol}'.format(
 | 
				
			||||||
| 
						 | 
					@ -377,6 +363,31 @@ class OpenNebulaManager():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return vm_terminated
 | 
					        return vm_terminated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_key_in_opennebula_user(self, ssh_key, update_type=1):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Save the given ssh key in OpenNebula user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Update type: 0: Replace the whole template.
 | 
				
			||||||
 | 
					                       1: Merge new template with the existing one.
 | 
				
			||||||
 | 
					        :param ssh_key: The ssh key to be saved
 | 
				
			||||||
 | 
					        :param update_type: The update type as explained above
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return_value = self.oneadmin_client.call(
 | 
				
			||||||
 | 
					            'user.update',
 | 
				
			||||||
 | 
					            self.opennebula_user.id,
 | 
				
			||||||
 | 
					            '<CONTEXT><SSH_PUBLIC_KEY>%s</SSH_PUBLIC_KEY></CONTEXT>' % ssh_key,
 | 
				
			||||||
 | 
					            update_type
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        if type(return_value) == int:
 | 
				
			||||||
 | 
					            logger.debug(
 | 
				
			||||||
 | 
					                "Saved the key in opennebula successfully : %s" % return_value)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            logger.error(
 | 
				
			||||||
 | 
					                "Could not save the key in opennebula. %s" % return_value)
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _get_template_pool(self):
 | 
					    def _get_template_pool(self):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            template_pool = oca.VmTemplatePool(self.oneadmin_client)
 | 
					            template_pool = oca.VmTemplatePool(self.oneadmin_client)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue