From 17557fd4c98d36ed626914695dc0e17702769333 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 09:52:53 +0530 Subject: [PATCH 01/10] Create refactored method handle_metadata_and_emails --- .../commands/fix_vm_after_celery_error.py | 0 datacenterlight/tasks.py | 232 ++++++++++-------- 2 files changed, 126 insertions(+), 106 deletions(-) create mode 100644 datacenterlight/management/commands/fix_vm_after_celery_error.py diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py new file mode 100644 index 00000000..e69de29b diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py index f080da90..9c98b729 100644 --- a/datacenterlight/tasks.py +++ b/datacenterlight/tasks.py @@ -56,11 +56,6 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id): "Running create_vm_task on {}".format(current_task.request.hostname)) vm_id = None try: - final_price = ( - specs.get('total_price') if 'total_price' in specs - else specs.get('price') - ) - if 'pass' in user: on_user = user.get('username') on_pass = user.get('pass') @@ -92,107 +87,8 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id): if vm_id is None: raise Exception("Could not create VM") - # Update HostingOrder with the created vm_id - hosting_order = HostingOrder.objects.filter(id=order_id).first() - error_msg = None - - try: - hosting_order.vm_id = vm_id - hosting_order.save() - logger.debug( - "Updated hosting_order {} with vm_id={}".format( - hosting_order.id, vm_id - ) - ) - except Exception as ex: - error_msg = ( - "HostingOrder with id {order_id} not found. This means that " - "the hosting order was not created and/or it is/was not " - "associated with VM with id {vm_id}. Details {details}".format( - order_id=order_id, vm_id=vm_id, details=str(ex) - ) - ) - logger.error(error_msg) - - stripe_utils = StripeUtils() - result = stripe_utils.set_subscription_metadata( - subscription_id=hosting_order.subscription_id, - metadata={"VM_ID": str(vm_id)} - ) - - if result.get('error') is not None: - emsg = "Could not update subscription metadata for {sub}".format( - sub=hosting_order.subscription_id - ) - logger.error(emsg) - if error_msg: - error_msg += ". " + emsg - else: - error_msg = emsg - - 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': final_price, - 'template': template.get('name'), - 'vm_name': vm.get('name'), - 'vm_id': vm['vm_id'], - 'order_id': order_id - } - - if error_msg: - context['errors'] = error_msg - if 'pricing_name' in specs: - context['pricing'] = str(VMPricing.get_vm_pricing_by_name( - name=specs['pricing_name'] - )) - email_data = { - 'subject': settings.DCL_TEXT + " Order from %s" % context['email'], - 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, - 'to': ['info@ungleich.ch'], - 'body': "\n".join( - ["%s=%s" % (k, v) for (k, v) in context.items()]), - 'reply_to': [context['email']], - } - email = EmailMessage(**email_data) - email.send() - - if 'pass' in user: - lang = 'en-us' - if user.get('language') is not None: - logger.debug( - "Language is set to {}".format(user.get('language'))) - lang = user.get('language') - translation.activate(lang) - # 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')), - 'order_url': reverse('hosting:invoices'), - 'page_header': _( - 'Your New VM %(vm_name)s at Data Center Light') % { - 'vm_name': vm.get('name')}, - 'vm_name': vm.get('name') - } - 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() - - logger.debug("New VM ID is {vm_id}".format(vm_id=vm_id)) - if vm_id > 0: - get_or_create_vm_detail(custom_user, manager, vm_id) + handle_metadata_and_emails(order_id, vm_id, manager, user, specs, + template) except Exception as e: logger.error(str(e)) try: @@ -214,3 +110,127 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id): return return vm_id + + +def handle_metadata_and_emails(order_id, vm_id, manager, user, specs, + template): + """ + Handle's setting up of the metadata in Stripe and database and sending of + emails to the user after VM creation + + :param order_id: the hosting order id + :param vm_id: the id of the vm created + :param manager: the OpenNebula Manager instance + :param user: the user's dict passed to the celery task + :param specs: the specification's dict passed to the celery task + :param template: the template dict passed to the celery task + + :return: + """ + + custom_user = CustomUser.objects.get(email=user.get('email')) + final_price = ( + specs.get('total_price') if 'total_price' in specs + else specs.get('price') + ) + # Update HostingOrder with the created vm_id + hosting_order = HostingOrder.objects.filter(id=order_id).first() + error_msg = None + + try: + hosting_order.vm_id = vm_id + hosting_order.save() + logger.debug( + "Updated hosting_order {} with vm_id={}".format( + hosting_order.id, vm_id + ) + ) + except Exception as ex: + error_msg = ( + "HostingOrder with id {order_id} not found. This means that " + "the hosting order was not created and/or it is/was not " + "associated with VM with id {vm_id}. Details {details}".format( + order_id=order_id, vm_id=vm_id, details=str(ex) + ) + ) + logger.error(error_msg) + + stripe_utils = StripeUtils() + result = stripe_utils.set_subscription_metadata( + subscription_id=hosting_order.subscription_id, + metadata={"VM_ID": str(vm_id)} + ) + + if result.get('error') is not None: + emsg = "Could not update subscription metadata for {sub}".format( + sub=hosting_order.subscription_id + ) + logger.error(emsg) + if error_msg: + error_msg += ". " + emsg + else: + error_msg = emsg + + 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': final_price, + 'template': template.get('name'), + 'vm_name': vm.get('name'), + 'vm_id': vm['vm_id'], + 'order_id': order_id + } + + if error_msg: + context['errors'] = error_msg + if 'pricing_name' in specs: + context['pricing'] = str(VMPricing.get_vm_pricing_by_name( + name=specs['pricing_name'] + )) + email_data = { + 'subject': settings.DCL_TEXT + " Order from %s" % context['email'], + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': ['info@ungleich.ch'], + 'body': "\n".join( + ["%s=%s" % (k, v) for (k, v) in context.items()]), + 'reply_to': [context['email']], + } + email = EmailMessage(**email_data) + email.send() + + if 'pass' in user: + lang = 'en-us' + if user.get('language') is not None: + logger.debug( + "Language is set to {}".format(user.get('language'))) + lang = user.get('language') + translation.activate(lang) + # 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')), + 'order_url': reverse('hosting:invoices'), + 'page_header': _( + 'Your New VM %(vm_name)s at Data Center Light') % { + 'vm_name': vm.get('name')}, + 'vm_name': vm.get('name') + } + 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() + + logger.debug("New VM ID is {vm_id}".format(vm_id=vm_id)) + if vm_id > 0: + get_or_create_vm_detail(custom_user, manager, vm_id) \ No newline at end of file From 082c0b00affbc3c7c49ae13727d702931a425fcf Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 09:53:14 +0530 Subject: [PATCH 02/10] Implement fix_vm_after_celery_error --- .../commands/fix_vm_after_celery_error.py | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py index e69de29b..97df553e 100644 --- a/datacenterlight/management/commands/fix_vm_after_celery_error.py +++ b/datacenterlight/management/commands/fix_vm_after_celery_error.py @@ -0,0 +1,71 @@ +from django.core.management.base import BaseCommand +from datacenterlight.tasks import handle_metadata_and_emails +from opennebula_api.models import OpenNebulaManager +import logging +import json + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = '''Updates the DB after manual creation of VM''' + + def add_arguments(self, parser): + parser.add_argument('vm_id', type=int) + parser.add_argument('order_id', type=int) + parser.add_argument('specs', type=str) + + def handle(self, *args, **options): + vm_id = options['vm_id'] + order_id = options['order_id'] + user_str = options['user'] + specs_str = options['specs'] + template_str = options['template'] + + json_acceptable_string = user_str.replace("'", "\"") + user = json.loads(json_acceptable_string) + + json_acceptable_string = specs_str.replace("'", "\"") + specs = json.loads(json_acceptable_string) + + json_acceptable_string = template_str.replace("'", "\"") + template = json.loads(json_acceptable_string) + if vm_id <= 0: + self.stdout.write(self.style.ERROR( + 'vm_id can\'t be less than or 0. Given: %s' % vm_id)) + return + if vm_id <= 0: + self.stdout.write(self.style.ERROR( + 'order_id can\'t be less than or 0. Given: %s' % vm_id)) + return + if specs_str is None or specs_str == "": + self.stdout.write( + self.style.ERROR('specs can\'t be empty or None')) + return + + user = { + 'name': user['name'], + 'email': user['email'], + 'username': user['username'], + 'pass': user['password'], + 'request_scheme': user['request_scheme'], + 'request_host': user['request_host'], + 'language': user['language'], + } + + on_user = user.get('username') + on_pass = user.get('pass') + + # Create OpenNebulaManager + manager = OpenNebulaManager(email=on_user, password=on_pass) + handle_metadata_and_emails(order_id, vm_id, manager, user, specs, + template) + self.stdout.write( + self.style.SUCCESS( + 'Done handling metadata and emails for %s %s %s' % ( + order_id, + vm_id, + str(user) + ) + ) + ) From 81ba834b0178c2b75707487ab14ee65d9c8b3c61 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 10:31:45 +0530 Subject: [PATCH 03/10] Add missing arguments --- .../management/commands/fix_vm_after_celery_error.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py index 97df553e..2f7325f4 100644 --- a/datacenterlight/management/commands/fix_vm_after_celery_error.py +++ b/datacenterlight/management/commands/fix_vm_after_celery_error.py @@ -13,7 +13,9 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument('vm_id', type=int) parser.add_argument('order_id', type=int) + parser.add_argument('user', type=str) parser.add_argument('specs', type=str) + parser.add_argument('template', type=str) def handle(self, *args, **options): vm_id = options['vm_id'] From 591f5ff37b5308f21ce7001df0fc9adf712c32d2 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 10:37:00 +0530 Subject: [PATCH 04/10] Fix key --- .../management/commands/fix_vm_after_celery_error.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py index 2f7325f4..1ba37152 100644 --- a/datacenterlight/management/commands/fix_vm_after_celery_error.py +++ b/datacenterlight/management/commands/fix_vm_after_celery_error.py @@ -49,7 +49,7 @@ class Command(BaseCommand): 'name': user['name'], 'email': user['email'], 'username': user['username'], - 'pass': user['password'], + 'pass': user['pass'], 'request_scheme': user['request_scheme'], 'request_host': user['request_host'], 'language': user['language'], From bbb51b71a6f200913428e09af2a59f707135bb48 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 10:40:55 +0530 Subject: [PATCH 05/10] Fix variable name --- .../commands/fix_vm_after_celery_error.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py index 1ba37152..f64963f6 100644 --- a/datacenterlight/management/commands/fix_vm_after_celery_error.py +++ b/datacenterlight/management/commands/fix_vm_after_celery_error.py @@ -25,7 +25,7 @@ class Command(BaseCommand): template_str = options['template'] json_acceptable_string = user_str.replace("'", "\"") - user = json.loads(json_acceptable_string) + user_dict = json.loads(json_acceptable_string) json_acceptable_string = specs_str.replace("'", "\"") specs = json.loads(json_acceptable_string) @@ -46,13 +46,13 @@ class Command(BaseCommand): return user = { - 'name': user['name'], - 'email': user['email'], - 'username': user['username'], - 'pass': user['pass'], - 'request_scheme': user['request_scheme'], - 'request_host': user['request_host'], - 'language': user['language'], + 'name': user_dict['name'], + 'email': user_dict['email'], + 'username': user_dict['username'], + 'pass': user_dict['pass'], + 'request_scheme': user_dict['request_scheme'], + 'request_host': user_dict['request_host'], + 'language': user_dict['language'], } on_user = user.get('username') From ff28c6e8e8c6ded30c6792207475b1112a3e5a41 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 10:44:20 +0530 Subject: [PATCH 06/10] Add log message --- .../management/commands/fix_vm_after_celery_error.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py index f64963f6..94c59868 100644 --- a/datacenterlight/management/commands/fix_vm_after_celery_error.py +++ b/datacenterlight/management/commands/fix_vm_after_celery_error.py @@ -59,6 +59,9 @@ class Command(BaseCommand): on_pass = user.get('pass') # Create OpenNebulaManager + self.style.SUCCESS( + 'Connecting using %s %s' % (on_user, on_pass) + ) manager = OpenNebulaManager(email=on_user, password=on_pass) handle_metadata_and_emails(order_id, vm_id, manager, user, specs, template) From 8c374af4ffa96f880e2ccac6f5418849d3fe738d Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 10:45:51 +0530 Subject: [PATCH 07/10] More logging --- datacenterlight/management/commands/fix_vm_after_celery_error.py | 1 + 1 file changed, 1 insertion(+) diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py index 94c59868..b8c71f8d 100644 --- a/datacenterlight/management/commands/fix_vm_after_celery_error.py +++ b/datacenterlight/management/commands/fix_vm_after_celery_error.py @@ -62,6 +62,7 @@ class Command(BaseCommand): self.style.SUCCESS( 'Connecting using %s %s' % (on_user, on_pass) ) + print('Connecting using %s %s' % (on_user, on_pass)) manager = OpenNebulaManager(email=on_user, password=on_pass) handle_metadata_and_emails(order_id, vm_id, manager, user, specs, template) From 9d85c058da82aad3a2026e670b9ddcfb620ad3a5 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 10:48:48 +0530 Subject: [PATCH 08/10] Fetch correct cred --- .../management/commands/fix_vm_after_celery_error.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py index b8c71f8d..3286db3a 100644 --- a/datacenterlight/management/commands/fix_vm_after_celery_error.py +++ b/datacenterlight/management/commands/fix_vm_after_celery_error.py @@ -1,6 +1,7 @@ from django.core.management.base import BaseCommand from datacenterlight.tasks import handle_metadata_and_emails from opennebula_api.models import OpenNebulaManager +from membership.models import CustomUser import logging import json @@ -54,16 +55,13 @@ class Command(BaseCommand): 'request_host': user_dict['request_host'], 'language': user_dict['language'], } - - on_user = user.get('username') - on_pass = user.get('pass') - + cu = CustomUser.objects.get(username=user.get('username')) # Create OpenNebulaManager self.style.SUCCESS( - 'Connecting using %s %s' % (on_user, on_pass) + 'Connecting using %s %s' % (cu.username, cu.password) ) - print('Connecting using %s %s' % (on_user, on_pass)) - manager = OpenNebulaManager(email=on_user, password=on_pass) + print('Connecting using %s %s' % (cu.username, cu.password)) + manager = OpenNebulaManager(email=cu.username, password=cu.password) handle_metadata_and_emails(order_id, vm_id, manager, user, specs, template) self.stdout.write( From 7bcca15f0b9fc4b6755774b9e78b67198e291ee7 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 10:52:06 +0530 Subject: [PATCH 09/10] Cleanup logging --- .../management/commands/fix_vm_after_celery_error.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/datacenterlight/management/commands/fix_vm_after_celery_error.py b/datacenterlight/management/commands/fix_vm_after_celery_error.py index 3286db3a..0cfdb423 100644 --- a/datacenterlight/management/commands/fix_vm_after_celery_error.py +++ b/datacenterlight/management/commands/fix_vm_after_celery_error.py @@ -57,10 +57,11 @@ class Command(BaseCommand): } cu = CustomUser.objects.get(username=user.get('username')) # Create OpenNebulaManager - self.style.SUCCESS( - 'Connecting using %s %s' % (cu.username, cu.password) + self.stdout.write( + self.style.SUCCESS( + 'Connecting using %s' % (cu.username) + ) ) - print('Connecting using %s %s' % (cu.username, cu.password)) manager = OpenNebulaManager(email=cu.username, password=cu.password) handle_metadata_and_emails(order_id, vm_id, manager, user, specs, template) From a0ab436d9abeba91d0bf3f21babdb368454b48c9 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 7 Dec 2020 11:36:34 +0530 Subject: [PATCH 10/10] Update Changelog for 2.14 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index fdadadf1..b54713fe 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,5 @@ +2.14: 2020-12-07 + * 8692: Create a script that fixes django db for the order after celery error (MR!743) 2.13: 2020-12-02 * 8654: Fix 500 error on invoices list for the user contact+devuanhosting.com@virus.media (MR!742) * 8593: Escape user's ssh key in xml-rpc call to create VM (MR!741)