From a662b1fe293e51b7ec6c452fde7c7eca42879ddd Mon Sep 17 00:00:00 2001 From: meow Date: Wed, 4 Mar 2020 13:25:46 +0500 Subject: [PATCH] Make migrate-one-vm-to-regular command idempotent --- .../commands/migrate-one-vm-to-regular.py | 104 ++++++++++-------- uncloud/opennebula/models.py | 2 +- .../migrations/0014_vmproduct_vmid.py | 18 +++ uncloud/uncloud_vm/models.py | 1 + 4 files changed, 80 insertions(+), 45 deletions(-) create mode 100644 uncloud/uncloud_vm/migrations/0014_vmproduct_vmid.py diff --git a/uncloud/opennebula/management/commands/migrate-one-vm-to-regular.py b/uncloud/opennebula/management/commands/migrate-one-vm-to-regular.py index 13f292b..68cf1f2 100644 --- a/uncloud/opennebula/management/commands/migrate-one-vm-to-regular.py +++ b/uncloud/opennebula/management/commands/migrate-one-vm-to-regular.py @@ -8,6 +8,19 @@ from uncloud_vm.models import VMHost, VMProduct, VMNetworkCard, VMDiskImageProdu from uncloud_pay.models import Order +def convert_mac_to_int(mac_address: str): + # Remove octet connecting characters + mac_address = mac_address.replace(':', '') + mac_address = mac_address.replace('.', '') + mac_address = mac_address.replace('-', '') + mac_address = mac_address.replace(' ', '') + + # Parse the resulting number as hexadecimal + mac_address = int(mac_address, base=16) + + return mac_address + + def get_vm_price(core, ram, storage, n_of_ipv4, n_of_ipv6): storage = storage / 10 # Division by 10 because our base storage unit is 10 GB total = 3 * core + 4 * ram + 3.5 * storage + 8 * n_of_ipv4 + 0 * n_of_ipv6 @@ -20,20 +33,11 @@ def get_vm_price(core, ram, storage, n_of_ipv4, n_of_ipv6): def create_nics(one_vm, vm_product): for nic in one_vm.nics: - mac_address = nic.get('MAC') + mac_address = convert_mac_to_int(nic.get('MAC')) ip_address = nic.get('IP', None) or nic.get('IP6_GLOBAL', None) - # Remove octet connecting characters - mac_address = mac_address.replace(':', '') - mac_address = mac_address.replace('.', '') - mac_address = mac_address.replace('-', '') - mac_address = mac_address.replace(' ', '') - - # Parse the resulting number as hexadecimal - mac_address = int(mac_address, base=16) - - VMNetworkCard.objects.create( - mac_address=mac_address, vm=vm_product, ip_address=ip_address + VMNetworkCard.objects.update_or_create( + mac_address=mac_address, vm=vm_product, defaults={'ip_address': ip_address} ) @@ -43,9 +47,7 @@ def create_disk_and_image(one_vm, vm_product): name = disk.get('image') # TODO: Fix the following hard coded values - is_os_image = True - is_public = True - status = 'active' + is_os_image, is_public, status = True, True, 'active' image_size_in_gb = disk.get('image_size_in_gb') disk_size_in_gb = disk.get('size_in_gb') @@ -53,22 +55,31 @@ def create_disk_and_image(one_vm, vm_product): image_source = disk.get('source') image_source_type = disk.get('source_type') - image = VMDiskImageProduct.objects.create( - owner=owner, name=name, is_os_image=is_os_image, is_public=is_public, - size_in_gb=image_size_in_gb, storage_class=storage_class, - image_source=image_source, image_source_type=image_source_type, status=status + image, _ = VMDiskImageProduct.objects.update_or_create( + name=name, + defaults={ + 'owner': owner, + 'is_os_image': is_os_image, + 'is_public': is_public, + 'size_in_gb': image_size_in_gb, + 'storage_class': storage_class, + 'image_source': image_source, + 'image_source_type': image_source_type, + 'status': status + } ) - vm_disk = VMDiskProduct.objects.create( - owner=owner, vm=vm_product, image=image, size_in_gb=disk_size_in_gb + VMDiskProduct.objects.update_or_create( + owner=owner, vm=vm_product, + defaults={ + 'image': image, + 'size_in_gb': disk_size_in_gb + } ) class Command(BaseCommand): help = 'Migrate Opennebula VM to regular (uncloud) vm' - def add_arguments(self, parser): - pass - def handle(self, *args, **options): for one_vm in VMModel.objects.all(): # Host on which the VM is currently residing @@ -76,7 +87,8 @@ class Command(BaseCommand): # VCPU, RAM, Owner, Status # TODO: Set actual status instead of hard coded 'active' - cores, ram_in_gb, owner, status = one_vm.cores, one_vm.ram_in_gb, one_vm.owner, 'active' + vm_id, cores, ram_in_gb = one_vm.vmid, one_vm.cores, one_vm.ram_in_gb + owner, status = one_vm.owner, 'active' # Total Amount of SSD Storage # TODO: What would happen if the attached storage is not SSD but HDD? @@ -96,25 +108,29 @@ class Command(BaseCommand): recurring_period = 'per_month' recurring_price = get_vm_price(cores, ram_in_gb, total_storage_in_gb, len(ipv4), len(ipv6)) - - order = Order.objects.create( - owner=one_vm.owner, - creation_date=creation_date, - starting_date=starting_date, - ending_date=ending_date, - one_time_price=one_time_price, - recurring_price=recurring_price, - recurring_period=recurring_period - ) - - vm_product = VMProduct.objects.create( - cores=cores, - ram_in_gb=ram_in_gb, - owner=one_vm.owner, - vmhost=host, - order=order, - status=status - ) + try: + vm_product = VMProduct.objects.get(vmid=vm_id) + except VMProduct.DoesNotExist: + order = Order.objects.create( + owner=one_vm.owner, + creation_date=creation_date, + starting_date=starting_date, + ending_date=ending_date, + one_time_price=one_time_price, + recurring_price=recurring_price, + recurring_period=recurring_period + ) + vm_product, _ = VMProduct.objects.update_or_create( + vmid=vm_id, + defaults={ + 'cores': cores, + 'ram_in_gb': ram_in_gb, + 'owner': owner, + 'vmhost': host, + 'order': order, + 'status': status + } + ) # Create VMNetworkCards create_nics(one_vm, vm_product) diff --git a/uncloud/opennebula/models.py b/uncloud/opennebula/models.py index 059ba5a..e69b4d0 100644 --- a/uncloud/opennebula/models.py +++ b/uncloud/opennebula/models.py @@ -19,7 +19,7 @@ class VM(models.Model): @property def ram_in_gb(self): - return (int(self.data['TEMPLATE']['MEMORY'])/1024.) + return int(self.data['TEMPLATE']['MEMORY'])/1024.0 @property def disks(self): diff --git a/uncloud/uncloud_vm/migrations/0014_vmproduct_vmid.py b/uncloud/uncloud_vm/migrations/0014_vmproduct_vmid.py new file mode 100644 index 0000000..4f43f77 --- /dev/null +++ b/uncloud/uncloud_vm/migrations/0014_vmproduct_vmid.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.3 on 2020-03-04 07:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_vm', '0013_auto_20200303_1845'), + ] + + operations = [ + migrations.AddField( + model_name='vmproduct', + name='vmid', + field=models.IntegerField(null=True), + ), + ] diff --git a/uncloud/uncloud_vm/models.py b/uncloud/uncloud_vm/models.py index 72317be..772c021 100644 --- a/uncloud/uncloud_vm/models.py +++ b/uncloud/uncloud_vm/models.py @@ -53,6 +53,7 @@ class VMProduct(Product): cores = models.IntegerField() ram_in_gb = models.FloatField() + vmid = models.IntegerField(null=True) class VMWithOSProduct(VMProduct):