| 
									
										
										
										
											2017-09-09 18:19:09 +05:30
										 |  |  | from datetime import datetime | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from celery.exceptions import MaxRetriesExceededError | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | from celery.utils.log import get_task_logger | 
					
						
							| 
									
										
										
										
											2017-09-15 13:09:46 +02:00
										 |  |  | from celery import current_task | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | from django.conf import settings | 
					
						
							| 
									
										
										
										
											2017-09-09 18:19:09 +05:30
										 |  |  | from django.core.mail import EmailMessage | 
					
						
							| 
									
										
										
										
											2017-09-27 02:07:52 +05:30
										 |  |  | from django.core.urlresolvers import reverse | 
					
						
							| 
									
										
										
										
											2017-09-16 20:55:37 +05:30
										 |  |  | from django.utils import translation | 
					
						
							| 
									
										
										
										
											2017-09-16 19:30:31 +05:30
										 |  |  | from django.utils.translation import ugettext_lazy as _ | 
					
						
							| 
									
										
										
										
											2017-09-09 18:19:09 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | from dynamicweb.celery import app | 
					
						
							|  |  |  | from hosting.models import HostingOrder, HostingBill | 
					
						
							| 
									
										
										
										
											2017-09-15 11:32:17 +02:00
										 |  |  | from membership.models import StripeCustomer, CustomUser | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | from opennebula_api.models import OpenNebulaManager | 
					
						
							|  |  |  | from opennebula_api.serializers import VirtualMachineSerializer | 
					
						
							| 
									
										
										
										
											2017-09-25 00:02:36 +05:30
										 |  |  | from utils.hosting_utils import get_all_public_keys, get_or_create_vm_detail | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | from utils.forms import UserBillingAddressForm | 
					
						
							| 
									
										
										
										
											2017-09-16 19:30:31 +05:30
										 |  |  | from utils.mailer import BaseEmail | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | from utils.models import BillingAddress | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-16 01:29:07 +02:00
										 |  |  | from .models import VMPricing | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | logger = get_task_logger(__name__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def retry_task(task, exception=None): | 
					
						
							|  |  |  |     """Retries the specified task using a "backing off countdown",
 | 
					
						
							|  |  |  |     meaning that the interval between retries grows exponentially | 
					
						
							|  |  |  |     with every retry. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Arguments: | 
					
						
							|  |  |  |         task: | 
					
						
							|  |  |  |             The task to retry. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         exception: | 
					
						
							|  |  |  |             Optionally, the exception that caused the retry. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def backoff(attempts): | 
					
						
							|  |  |  |         return 2 ** attempts | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     kwargs = { | 
					
						
							|  |  |  |         'countdown': backoff(task.request.retries), | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if exception: | 
					
						
							|  |  |  |         kwargs['exc'] = exception | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 21:54:12 +02:00
										 |  |  |     raise task.retry(**kwargs) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 21:54:12 +02:00
										 |  |  | @app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES) | 
					
						
							| 
									
										
										
										
											2017-08-23 20:12:50 +02:00
										 |  |  | def create_vm_task(self, vm_template_id, user, specs, template, | 
					
						
							|  |  |  |                    stripe_customer_id, billing_address_data, | 
					
						
							| 
									
										
										
										
											2017-09-29 08:37:25 +02:00
										 |  |  |                    stripe_subscription_id, cc_details): | 
					
						
							| 
									
										
										
										
											2017-09-23 13:09:14 +05:30
										 |  |  |     logger.debug( | 
					
						
							|  |  |  |         "Running create_vm_task on {}".format(current_task.request.hostname)) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:52:23 +02:00
										 |  |  |     vm_id = None | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2018-04-16 01:26:19 +02:00
										 |  |  |         final_price = (specs.get('total_price') if 'total_price' in specs | 
					
						
							|  |  |  |                        else specs.get('price')) | 
					
						
							| 
									
										
										
										
											2017-09-29 08:37:25 +02:00
										 |  |  |         billing_address = BillingAddress( | 
					
						
							|  |  |  |             cardholder_name=billing_address_data['cardholder_name'], | 
					
						
							|  |  |  |             street_address=billing_address_data['street_address'], | 
					
						
							|  |  |  |             city=billing_address_data['city'], | 
					
						
							|  |  |  |             postal_code=billing_address_data['postal_code'], | 
					
						
							|  |  |  |             country=billing_address_data['country'] | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         billing_address.save() | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() | 
					
						
							| 
									
										
										
										
											2017-09-10 15:26:29 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 20:46:43 +05:30
										 |  |  |         if 'pass' in user: | 
					
						
							| 
									
										
										
										
											2017-09-10 15:26:29 +05:30
										 |  |  |             on_user = user.get('email') | 
					
						
							|  |  |  |             on_pass = user.get('pass') | 
					
						
							|  |  |  |             logger.debug("Using user {user} to create VM".format(user=on_user)) | 
					
						
							| 
									
										
										
										
											2017-09-10 14:52:06 +05:30
										 |  |  |             vm_name = None | 
					
						
							| 
									
										
										
										
											2017-09-09 20:46:43 +05:30
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2017-09-10 15:26:29 +05:30
										 |  |  |             on_user = settings.OPENNEBULA_USERNAME | 
					
						
							|  |  |  |             on_pass = settings.OPENNEBULA_PASSWORD | 
					
						
							| 
									
										
										
										
											2017-09-09 18:19:09 +05:30
										 |  |  |             logger.debug("Using OpenNebula admin user to create VM") | 
					
						
							| 
									
										
										
										
											2017-09-10 14:52:06 +05:30
										 |  |  |             vm_name = "{email}-{template_name}-{date}".format( | 
					
						
							|  |  |  |                 email=user.get('email'), | 
					
						
							|  |  |  |                 template_name=template.get('name'), | 
					
						
							|  |  |  |                 date=int(datetime.now().strftime("%s"))) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 15:26:29 +05:30
										 |  |  |         # Create OpenNebulaManager | 
					
						
							|  |  |  |         manager = OpenNebulaManager(email=on_user, password=on_pass) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         vm_id = manager.create_vm( | 
					
						
							|  |  |  |             template_id=vm_template_id, | 
					
						
							|  |  |  |             specs=specs, | 
					
						
							| 
									
										
										
										
											2017-08-19 18:02:55 +05:30
										 |  |  |             ssh_key=settings.ONEADMIN_USER_SSH_PUBLIC_KEY, | 
					
						
							| 
									
										
										
										
											2017-09-10 14:52:06 +05:30
										 |  |  |             vm_name=vm_name | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 18:52:23 +02:00
										 |  |  |         if vm_id is None: | 
					
						
							|  |  |  |             raise Exception("Could not create VM") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-16 05:03:48 +02:00
										 |  |  |         vm_pricing = VMPricing.get_vm_pricing_by_name( | 
					
						
							|  |  |  |             name=specs['pricing_name'] | 
					
						
							|  |  |  |         ) if 'pricing_name' in specs else VMPricing.get_default_pricing() | 
					
						
							|  |  |  |         # Create a Hosting Order | 
					
						
							|  |  |  |         order = HostingOrder.create( | 
					
						
							|  |  |  |             price=final_price, | 
					
						
							|  |  |  |             vm_id=vm_id, | 
					
						
							|  |  |  |             customer=customer, | 
					
						
							|  |  |  |             billing_address=billing_address, | 
					
						
							|  |  |  |             vm_pricing=vm_pricing | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Create a Hosting Bill | 
					
						
							|  |  |  |         HostingBill.create( | 
					
						
							| 
									
										
										
										
											2018-04-16 05:03:48 +02:00
										 |  |  |             customer=customer, billing_address=billing_address | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Create Billing Address for User if he does not have one | 
					
						
							|  |  |  |         if not customer.user.billing_addresses.count(): | 
					
						
							|  |  |  |             billing_address_data.update({ | 
					
						
							|  |  |  |                 'user': customer.user.id | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             billing_address_user_form = UserBillingAddressForm( | 
					
						
							|  |  |  |                 billing_address_data) | 
					
						
							|  |  |  |             billing_address_user_form.is_valid() | 
					
						
							|  |  |  |             billing_address_user_form.save() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-21 01:54:55 +05:30
										 |  |  |         # Associate an order with a stripe subscription | 
					
						
							| 
									
										
										
										
											2017-09-29 08:37:25 +02:00
										 |  |  |         order.set_subscription_id(stripe_subscription_id, cc_details) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # If the Stripe payment succeeds, set order status approved | 
					
						
							|  |  |  |         order.set_approved() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         context = { | 
					
						
							|  |  |  |             'name': user.get('name'), | 
					
						
							|  |  |  |             'email': user.get('email'), | 
					
						
							|  |  |  |             'cores': specs.get('cpu'), | 
					
						
							|  |  |  |             'memory': specs.get('memory'), | 
					
						
							|  |  |  |             'storage': specs.get('disk_size'), | 
					
						
							| 
									
										
										
										
											2018-04-16 01:24:21 +02:00
										 |  |  |             'price': final_price, | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |             'template': template.get('name'), | 
					
						
							| 
									
										
										
										
											2017-09-27 03:28:06 +05:30
										 |  |  |             'vm_name': vm.get('name'), | 
					
						
							| 
									
										
										
										
											2017-09-27 02:07:52 +05:30
										 |  |  |             'vm_id': vm['vm_id'], | 
					
						
							|  |  |  |             'order_id': order.id | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-16 01:29:07 +02:00
										 |  |  |         if 'pricing_name' in specs: | 
					
						
							|  |  |  |             context['pricing'] = str(VMPricing.get_vm_pricing_by_name( | 
					
						
							|  |  |  |                 name=specs['pricing_name'] | 
					
						
							|  |  |  |             )) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         email_data = { | 
					
						
							|  |  |  |             'subject': settings.DCL_TEXT + " Order from %s" % context['email'], | 
					
						
							|  |  |  |             'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, | 
					
						
							|  |  |  |             'to': ['info@ungleich.ch'], | 
					
						
							| 
									
										
										
										
											2017-08-23 20:12:50 +02:00
										 |  |  |             'body': "\n".join( | 
					
						
							|  |  |  |                 ["%s=%s" % (k, v) for (k, v) in context.items()]), | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |             'reply_to': [context['email']], | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         email = EmailMessage(**email_data) | 
					
						
							|  |  |  |         email.send() | 
					
						
							| 
									
										
										
										
											2017-09-15 11:32:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-15 12:43:48 +05:30
										 |  |  |         if 'pass' in user: | 
					
						
							| 
									
										
										
										
											2017-09-27 02:07:52 +05:30
										 |  |  |             lang = 'en-us' | 
					
						
							| 
									
										
										
										
											2017-09-16 20:55:37 +05:30
										 |  |  |             if user.get('language') is not None: | 
					
						
							| 
									
										
										
										
											2017-09-23 13:09:14 +05:30
										 |  |  |                 logger.debug( | 
					
						
							|  |  |  |                     "Language is set to {}".format(user.get('language'))) | 
					
						
							| 
									
										
										
										
											2017-09-16 20:55:37 +05:30
										 |  |  |                 lang = user.get('language') | 
					
						
							|  |  |  |             translation.activate(lang) | 
					
						
							| 
									
										
										
										
											2017-09-16 19:30:31 +05:30
										 |  |  |             # Send notification to the user as soon as VM has been booked | 
					
						
							|  |  |  |             context = { | 
					
						
							|  |  |  |                 'base_url': "{0}://{1}".format(user.get('request_scheme'), | 
					
						
							|  |  |  |                                                user.get('request_host')), | 
					
						
							| 
									
										
										
										
											2017-09-27 02:07:52 +05:30
										 |  |  |                 'order_url': reverse('hosting:orders', | 
					
						
							|  |  |  |                                      kwargs={'pk': order.id}), | 
					
						
							| 
									
										
										
										
											2017-09-16 19:30:31 +05:30
										 |  |  |                 'page_header': _( | 
					
						
							|  |  |  |                     'Your New VM %(vm_name)s at Data Center Light') % { | 
					
						
							| 
									
										
										
										
											2017-09-27 03:36:02 +05:30
										 |  |  |                     'vm_name': vm.get('name')}, | 
					
						
							|  |  |  |                 'vm_name': vm.get('name') | 
					
						
							| 
									
										
										
										
											2017-09-16 19:30:31 +05:30
										 |  |  |             } | 
					
						
							|  |  |  |             email_data = { | 
					
						
							|  |  |  |                 'subject': context.get('page_header'), | 
					
						
							|  |  |  |                 'to': user.get('email'), | 
					
						
							|  |  |  |                 'context': context, | 
					
						
							|  |  |  |                 'template_name': 'new_booked_vm', | 
					
						
							|  |  |  |                 'template_path': 'hosting/emails/', | 
					
						
							|  |  |  |                 'from_address': settings.DCL_SUPPORT_FROM_ADDRESS, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             email = BaseEmail(**email_data) | 
					
						
							|  |  |  |             email.send() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-15 12:43:48 +05:30
										 |  |  |             # try to see if we have the IP and that if the ssh keys can | 
					
						
							|  |  |  |             # be configured | 
					
						
							|  |  |  |             new_host = manager.get_primary_ipv4(vm_id) | 
					
						
							| 
									
										
										
										
											2017-09-15 11:32:17 +02:00
										 |  |  |             logger.debug("New VM ID is {vm_id}".format(vm_id=vm_id)) | 
					
						
							| 
									
										
										
										
											2017-09-15 12:43:48 +05:30
										 |  |  |             if new_host is not None: | 
					
						
							| 
									
										
										
										
											2017-09-15 11:32:17 +02:00
										 |  |  |                 custom_user = CustomUser.objects.get(email=user.get('email')) | 
					
						
							| 
									
										
										
										
											2017-09-25 00:02:36 +05:30
										 |  |  |                 get_or_create_vm_detail(custom_user, manager, vm_id) | 
					
						
							| 
									
										
										
										
											2017-09-15 11:32:17 +02:00
										 |  |  |                 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( | 
					
						
							| 
									
										
										
										
											2017-09-29 08:37:25 +02:00
										 |  |  |                             "Calling configure on {host} for " | 
					
						
							|  |  |  |                             "{num_keys} keys".format( | 
					
						
							| 
									
										
										
										
											2017-09-15 11:32:17 +02:00
										 |  |  |                                 host=new_host, num_keys=len(keys))) | 
					
						
							|  |  |  |                         # Let's delay the task by 75 seconds to be sure | 
					
						
							|  |  |  |                         # that we run the cdist configure after the host | 
					
						
							|  |  |  |                         # is up | 
					
						
							|  |  |  |                         manager.manage_public_key(keys, | 
					
						
							|  |  |  |                                                   hosts=[new_host], | 
					
						
							|  |  |  |                                                   countdown=75) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |     except Exception as e: | 
					
						
							|  |  |  |         logger.error(str(e)) | 
					
						
							| 
									
										
										
										
											2017-08-06 21:54:12 +02:00
										 |  |  |         try: | 
					
						
							|  |  |  |             retry_task(self) | 
					
						
							|  |  |  |         except MaxRetriesExceededError: | 
					
						
							| 
									
										
										
										
											2017-08-23 20:12:50 +02:00
										 |  |  |             msg_text = 'Finished {} retries for create_vm_task'.format( | 
					
						
							|  |  |  |                 self.request.retries) | 
					
						
							| 
									
										
										
										
											2017-08-06 21:54:12 +02:00
										 |  |  |             logger.error(msg_text) | 
					
						
							|  |  |  |             # Try sending email and stop | 
					
						
							|  |  |  |             email_data = { | 
					
						
							| 
									
										
										
										
											2017-08-23 20:12:50 +02:00
										 |  |  |                 'subject': '{} CELERY TASK ERROR: {}'.format(settings.DCL_TEXT, | 
					
						
							|  |  |  |                                                              msg_text), | 
					
						
							| 
									
										
										
										
											2017-09-15 13:09:46 +02:00
										 |  |  |                 'from_email': current_task.request.hostname, | 
					
						
							|  |  |  |                 'to': settings.DCL_ERROR_EMAILS_TO_LIST, | 
					
						
							| 
									
										
										
										
											2017-08-06 22:19:27 +02:00
										 |  |  |                 'body': ',\n'.join(str(i) for i in self.request.args) | 
					
						
							| 
									
										
										
										
											2017-08-06 21:54:12 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             email = EmailMessage(**email_data) | 
					
						
							|  |  |  |             email.send() | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 18:52:23 +02:00
										 |  |  |     return vm_id |