| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | from dynamicweb.celery import app | 
					
						
							|  |  |  | from celery.utils.log import get_task_logger | 
					
						
							|  |  |  | from django.conf import settings | 
					
						
							|  |  |  | from opennebula_api.models import OpenNebulaManager | 
					
						
							|  |  |  | from opennebula_api.serializers import VirtualMachineSerializer | 
					
						
							|  |  |  | from hosting.models import HostingOrder, HostingBill | 
					
						
							|  |  |  | from utils.forms import UserBillingAddressForm | 
					
						
							|  |  |  | from datetime import datetime | 
					
						
							|  |  |  | from membership.models import StripeCustomer | 
					
						
							|  |  |  | from django.core.mail import EmailMessage | 
					
						
							|  |  |  | from utils.models import BillingAddress | 
					
						
							| 
									
										
										
										
											2017-08-06 21:54:12 +02:00
										 |  |  | from celery.exceptions import MaxRetriesExceededError | 
					
						
							| 
									
										
										
										
											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-08-06 18:42:27 +02:00
										 |  |  |                    billing_address_id, | 
					
						
							| 
									
										
										
										
											2017-08-24 11:49:41 +05:30
										 |  |  |                    charge, cc_details): | 
					
						
							| 
									
										
										
										
											2017-08-06 18:52:23 +02:00
										 |  |  |     vm_id = None | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |     try: | 
					
						
							|  |  |  |         final_price = specs.get('price') | 
					
						
							| 
									
										
										
										
											2017-08-23 20:12:50 +02:00
										 |  |  |         billing_address = BillingAddress.objects.filter( | 
					
						
							|  |  |  |             id=billing_address_id).first() | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() | 
					
						
							|  |  |  |         # Create OpenNebulaManager | 
					
						
							|  |  |  |         manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME, | 
					
						
							|  |  |  |                                     password=settings.OPENNEBULA_PASSWORD) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Create a vm using oneadmin, also specify the name | 
					
						
							|  |  |  |         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-08-06 18:42:27 +02:00
										 |  |  |             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:52:23 +02:00
										 |  |  |         if vm_id is None: | 
					
						
							|  |  |  |             raise Exception("Could not create VM") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         # Create a Hosting Order | 
					
						
							|  |  |  |         order = HostingOrder.create( | 
					
						
							|  |  |  |             price=final_price, | 
					
						
							|  |  |  |             vm_id=vm_id, | 
					
						
							|  |  |  |             customer=customer, | 
					
						
							|  |  |  |             billing_address=billing_address | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Create a Hosting Bill | 
					
						
							|  |  |  |         HostingBill.create( | 
					
						
							|  |  |  |             customer=customer, billing_address=billing_address) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 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-08-06 18:42:27 +02:00
										 |  |  |         charge_object = DictDotLookup(charge) | 
					
						
							| 
									
										
										
										
											2017-08-24 11:49:41 +05:30
										 |  |  |         order.set_subscription_id(charge_object, 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'), | 
					
						
							|  |  |  |             'price': specs.get('price'), | 
					
						
							|  |  |  |             'template': template.get('name'), | 
					
						
							|  |  |  |             'vm.name': vm['name'], | 
					
						
							|  |  |  |             'vm.id': vm['vm_id'], | 
					
						
							|  |  |  |             'order.id': order.id | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         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() | 
					
						
							|  |  |  |     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-08-06 21:54:12 +02:00
										 |  |  |                 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, | 
					
						
							|  |  |  |                 'to': ['info@ungleich.ch'], | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class DictDotLookup(object): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Creates objects that behave much like a dictionaries, but allow nested | 
					
						
							|  |  |  |     key access using object '.' (dot) lookups. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, d): | 
					
						
							|  |  |  |         for k in d: | 
					
						
							|  |  |  |             if isinstance(d[k], dict): | 
					
						
							|  |  |  |                 self.__dict__[k] = DictDotLookup(d[k]) | 
					
						
							|  |  |  |             elif isinstance(d[k], (list, tuple)): | 
					
						
							|  |  |  |                 l = [] | 
					
						
							|  |  |  |                 for v in d[k]: | 
					
						
							|  |  |  |                     if isinstance(v, dict): | 
					
						
							|  |  |  |                         l.append(DictDotLookup(v)) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         l.append(v) | 
					
						
							|  |  |  |                 self.__dict__[k] = l | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.__dict__[k] = d[k] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getitem__(self, name): | 
					
						
							|  |  |  |         if name in self.__dict__: | 
					
						
							|  |  |  |             return self.__dict__[name] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __iter__(self): | 
					
						
							|  |  |  |         return iter(self.__dict__.keys()) |