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