| 
									
										
										
										
											2017-09-09 18:19:09 +05:30
										 |  |  | from datetime import datetime | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-01 11:05:23 +02:00
										 |  |  | from celery import current_task | 
					
						
							| 
									
										
										
										
											2017-09-09 18:19:09 +05:30
										 |  |  | from celery.exceptions import MaxRetriesExceededError | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | from celery.utils.log import get_task_logger | 
					
						
							|  |  |  | 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 _ | 
					
						
							| 
									
										
										
										
											2018-08-21 23:49:47 +02:00
										 |  |  | from time import sleep | 
					
						
							| 
									
										
										
										
											2017-09-09 18:19:09 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | from dynamicweb.celery import app | 
					
						
							| 
									
										
										
										
											2018-07-01 16:25:02 +02:00
										 |  |  | from hosting.models import HostingOrder | 
					
						
							|  |  |  | from membership.models import CustomUser | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | from opennebula_api.models import OpenNebulaManager | 
					
						
							|  |  |  | from opennebula_api.serializers import VirtualMachineSerializer | 
					
						
							| 
									
										
										
										
											2018-08-22 00:14:17 +02:00
										 |  |  | from utils.hosting_utils import ( | 
					
						
							|  |  |  |     get_all_public_keys, get_or_create_vm_detail, ping_ok | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2017-09-16 19:30:31 +05:30
										 |  |  | from utils.mailer import BaseEmail | 
					
						
							| 
									
										
										
										
											2018-04-19 00:52:38 +02:00
										 |  |  | from utils.stripe_utils import StripeUtils | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2018-04-18 23:50:52 +02:00
										 |  |  | def create_vm_task(self, vm_template_id, user, specs, template, order_id): | 
					
						
							| 
									
										
										
										
											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-21 21:01:42 +05:30
										 |  |  |         final_price = ( | 
					
						
							|  |  |  |             specs.get('total_price') if 'total_price' in specs | 
					
						
							|  |  |  |             else specs.get('price') | 
					
						
							| 
									
										
										
										
											2017-09-29 08:37:25 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											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-18 23:50:52 +02:00
										 |  |  |         # Update HostingOrder with the created vm_id | 
					
						
							|  |  |  |         hosting_order = HostingOrder.objects.filter(id=order_id).first() | 
					
						
							|  |  |  |         error_msg = None | 
					
						
							| 
									
										
										
										
											2018-04-19 07:26:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             hosting_order.vm_id = vm_id | 
					
						
							|  |  |  |             hosting_order.save() | 
					
						
							| 
									
										
										
										
											2018-04-18 23:50:52 +02:00
										 |  |  |             logger.debug( | 
					
						
							| 
									
										
										
										
											2018-04-19 07:26:34 +02:00
										 |  |  |                 "Updated hosting_order {} with vm_id={}".format( | 
					
						
							| 
									
										
										
										
											2018-04-18 23:50:52 +02:00
										 |  |  |                     hosting_order.id, vm_id | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2018-04-19 07:26:34 +02:00
										 |  |  |         except Exception as ex: | 
					
						
							| 
									
										
										
										
											2018-04-18 23:50:52 +02:00
										 |  |  |             error_msg = ( | 
					
						
							|  |  |  |                 "HostingOrder with id {order_id} not found. This means that " | 
					
						
							|  |  |  |                 "the hosting order was not created and/or it is/was not " | 
					
						
							| 
									
										
										
										
											2018-04-19 07:26:34 +02:00
										 |  |  |                 "associated with VM with id {vm_id}. Details {details}".format( | 
					
						
							|  |  |  |                     order_id=order_id, vm_id=vm_id, details=str(ex) | 
					
						
							| 
									
										
										
										
											2018-04-18 23:50:52 +02:00
										 |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             logger.error(error_msg) | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 00:52:38 +02:00
										 |  |  |         stripe_utils = StripeUtils() | 
					
						
							|  |  |  |         result = stripe_utils.set_subscription_metadata( | 
					
						
							|  |  |  |             subscription_id=hosting_order.subscription_id, | 
					
						
							|  |  |  |             metadata={"VM_ID": str(vm_id)} | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2018-04-19 01:08:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if result.get('error') is not None: | 
					
						
							| 
									
										
										
										
											2018-04-19 00:52:38 +02:00
										 |  |  |             emsg = "Could not update subscription metadata for {sub}".format( | 
					
						
							| 
									
										
										
										
											2018-04-21 21:01:42 +05:30
										 |  |  |                 sub=hosting_order.subscription_id | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2018-04-19 00:52:38 +02:00
										 |  |  |             logger.error(emsg) | 
					
						
							|  |  |  |             if error_msg: | 
					
						
							| 
									
										
										
										
											2018-06-27 12:24:16 +02:00
										 |  |  |                 error_msg += ". " + emsg | 
					
						
							| 
									
										
										
										
											2018-04-19 00:52:38 +02:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 error_msg = emsg | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         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'], | 
					
						
							| 
									
										
										
										
											2018-04-18 23:50:52 +02:00
										 |  |  |             'order_id': order_id | 
					
						
							| 
									
										
										
										
											2017-08-06 18:42:27 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-18 23:50:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if error_msg: | 
					
						
							|  |  |  |             context['errors'] = error_msg | 
					
						
							| 
									
										
										
										
											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', | 
					
						
							| 
									
										
										
										
											2018-04-18 23:50:52 +02:00
										 |  |  |                                      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() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-01 11:07:29 +02:00
										 |  |  |             # 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) | 
					
						
							| 
									
										
										
										
											2017-09-15 11:32:17 +02:00
										 |  |  |             logger.debug("New VM ID is {vm_id}".format(vm_id=vm_id)) | 
					
						
							| 
									
										
										
										
											2018-07-01 11:07:29 +02:00
										 |  |  |             if vm_ipv6 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( | 
					
						
							| 
									
										
										
										
											2018-07-01 11:07:29 +02:00
										 |  |  |                                 host=vm_ipv6, num_keys=len(keys) | 
					
						
							|  |  |  |                             ) | 
					
						
							|  |  |  |                         ) | 
					
						
							| 
									
										
										
										
											2018-08-22 00:42:50 +02:00
										 |  |  |                         # Let's wait until the IP responds to ping before we | 
					
						
							|  |  |  |                         # run the cdist configure on the host | 
					
						
							| 
									
										
										
										
											2018-08-21 23:49:47 +02:00
										 |  |  |                         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) | 
					
						
							|  |  |  |                                 ) | 
					
						
							| 
									
										
										
										
											2018-08-22 00:25:59 +02:00
										 |  |  |                                 sleep(10) | 
					
						
							| 
									
										
										
										
											2018-08-21 23:49:47 +02:00
										 |  |  |                                 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: | 
					
						
							| 
									
										
										
										
											2018-08-22 00:37:40 +02:00
										 |  |  |                             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() | 
					
						
							| 
									
										
										
										
											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 |