From de2338dce94b741b0b2bcb6c01f72b0410279452 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franti=C5=A1ek=20=C5=98ezn=C3=AD=C4=8Dek?=
 <246254@mail.muni.cz>
Date: Tue, 5 Mar 2024 18:06:21 +0100
Subject: [PATCH] feat: add possibility to migrate standalone volumes

---
 ci/lib.py              | 191 +++++++++++++++++++++++++++++++++
 ci/project-migrator.py | 236 +++++++++--------------------------------
 2 files changed, 239 insertions(+), 188 deletions(-)

diff --git a/ci/lib.py b/ci/lib.py
index 2b76a30..0eab6d7 100644
--- a/ci/lib.py
+++ b/ci/lib.py
@@ -4,6 +4,8 @@ import json
 import re
 import pprint
 import time
+import os
+import os.path
 
 import xmltodict
 import paramiko
@@ -477,3 +479,192 @@ def get_server_floating_ip_port(ostack_connection, server):
                 if str(i_port_ip.get('ip_address')).startswith(i_ip_prefix):
                     return i_port
     return None
+
+
+def get_server_block_device_mapping(args, server_volume_attachment, server_volume, server_root_device_name):
+    """ return server block device mapping item """
+    return {'source': {'block_storage_type': 'openstack-volume-ceph-rbd-image',
+                       'volume_attachment_id': server_volume_attachment.id,
+                       'volume_id': server_volume.id,
+                       'ceph_pool_name': args.source_ceph_cinder_pool_name,
+                       'ceph_rbd_image_name': server_volume.id},
+            'destination': {'volume_size': server_volume.size,
+                            'volume_name': get_migrated_resource_name(args, server_volume.name),
+                            'volume_description': server_volume.description,
+                            'volume_id': None,
+                            'ceph_pool_name': args.destination_ceph_cinder_pool_name,
+                            'device_name': os.path.basename(server_volume_attachment.device),
+                            'volume_bootable': server_root_device_name == server_volume_attachment.device}}
+
+
+
+
+def migrate_rbd_image(args, server_block_device_mapping):
+    """ migrate G1 ceph RBD image to G2 ceph """
+
+    ## G1: detect existing G1 RBD image
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-exists.sh prod-ephemeral-vms 0069e95e-e805-44ff-bab5-872424312ff6
+    source_server_rbd_images, stderr, ecode = ceph_rbd_image_exists(args,
+                                                                        server_block_device_mapping['source']['ceph_pool_name'],
+                                                                        server_block_device_mapping['source']['ceph_rbd_image_name'])
+    log_or_assert(args, "G.1 Source OpenStack VM RBD image exists - query succeeded", ecode == 0, locals())
+    log_or_assert(args, "G.1 Source OpenStack VM RBD image exists - single image returned",
+                  source_server_rbd_images and len(source_server_rbd_images) == 1, locals())
+    source_server_rbd_image = source_server_rbd_images[0]
+
+
+    ## G2: find volume
+    #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-exists.sh cloud-cinder-volumes-prod-brno <g2-rbd-image-name>
+    destination_server_rbd_images, stderr, ecode = ceph_rbd_image_exists(args,
+                                                                                   server_block_device_mapping['destination']['ceph_pool_name'],
+                                                                                   server_block_device_mapping['destination']['volume_id'])
+    log_or_assert(args, "G.2 Destination OpenStack VM RBD image exists - query succeeded", ecode == 0, locals())
+    log_or_assert(args, "G.2 Destination OpenStack VM RBD image exists - single image returned",
+                  destination_server_rbd_images and len(destination_server_rbd_images) == 1, locals())
+    destination_server_rbd_image = destination_server_rbd_images[0]
+
+    ## G1: create RBD image protected snapshot
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-exists.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 1
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-create.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 0
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-exists.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 0
+    source_rbd_image_snapshot_name = f"g1-g2-migration-{source_server_rbd_image}"
+    stdout, stderr, ecode = ceph_rbd_image_snapshot_exists(args,
+                                                                    server_block_device_mapping['source']['ceph_pool_name'],
+                                                                    source_server_rbd_image,
+                                                                    source_rbd_image_snapshot_name)
+    log_or_assert(args,
+                  "G.3 Source OpenStack VM RBD image has non-colliding snapshot " \
+                  f"({server_block_device_mapping['source']['ceph_pool_name']}/{source_server_rbd_image}@{source_rbd_image_snapshot_name})",
+                  ecode != 0, locals())
+
+    stdout, stderr, ecode = ceph_rbd_image_snapshot_create(args,
+                                                                    server_block_device_mapping['source']['ceph_pool_name'],
+                                                                    source_server_rbd_image,
+                                                                    source_rbd_image_snapshot_name)
+    log_or_assert(args,
+                  "G.4 Source OpenStack VM RBD image snapshot created " \
+                  f"({server_block_device_mapping['source']['ceph_pool_name']}/{source_server_rbd_image}@{source_rbd_image_snapshot_name})",
+                  ecode == 0, locals())
+
+
+    stdout, stderr, ecode = ceph_rbd_image_snapshot_exists(args,
+                                                                    server_block_device_mapping['source']['ceph_pool_name'],
+                                                                    source_server_rbd_image,
+                                                                    source_rbd_image_snapshot_name)
+    log_or_assert(args,
+                  "G.5 Source OpenStack VM RBD image snapshot exists " \
+                  f"({server_block_device_mapping['source']['ceph_pool_name']}/{source_server_rbd_image}@{source_rbd_image_snapshot_name})",
+                  ecode == 0, locals())
+
+    ## G2: delete RBD image
+    #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-delete.sh cloud-cinder-volumes-prod-brno <g2-rbd-image-name>
+    ## G2: confirm volume is deleted
+    #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-exists.sh cloud-cinder-volumes-prod-brno <g2-rbd-image-name> # 1
+    stdout, stderr, ecode = ceph_rbd_image_delete(args,
+                                                        server_block_device_mapping['destination']['ceph_pool_name'],
+                                                        destination_server_rbd_image)
+    log_or_assert(args,
+                  f"G.6 Destination OpenStack VM RBD image deletion succeeded ({server_block_device_mapping['destination']['ceph_pool_name']}/{destination_server_rbd_image})",
+                  ecode == 0, locals())
+    stdout, stderr, ecode = ceph_rbd_image_exists(args,
+                                                        server_block_device_mapping['destination']['ceph_pool_name'],
+                                                        destination_server_rbd_image)
+    log_or_assert(args,
+                  f"G.7 Destination OpenStack VM RBD image does not exist ({server_block_device_mapping['destination']['ceph_pool_name']}/{destination_server_rbd_image})",
+                  ecode != 0, locals())
+
+
+    ## G1: clone from snapshot
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-clone.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-exists.sh prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk
+    source_rbd_cloned_image_name = f"g1-g2-migration-{source_server_rbd_image}"
+    stdout, stderr, ecode = ceph_rbd_image_clone(args,
+                                                        server_block_device_mapping['source']['ceph_pool_name'],
+                                                        source_server_rbd_image,
+                                                        source_rbd_image_snapshot_name,
+                                                        server_block_device_mapping['source']['ceph_pool_name'],
+                                                        source_rbd_cloned_image_name)
+    log_or_assert(args,
+                  "G.8 Source OpenStack VM RBD image cloned succesfully " \
+                  f"({server_block_device_mapping['source']['ceph_pool_name']}/{source_server_rbd_image}@{source_rbd_image_snapshot_name} -> {server_block_device_mapping['source']['ceph_pool_name']}/{source_rbd_cloned_image_name})",
+                  ecode == 0, locals())
+    stdout, stderr, ecode = ceph_rbd_image_exists(args,
+                                                        server_block_device_mapping['source']['ceph_pool_name'],
+                                                        source_rbd_cloned_image_name)
+    log_or_assert(args,
+                  f"G.9 Source OpenStack VM cloned RBD image exists ({server_block_device_mapping['source']['ceph_pool_name']}/{source_rbd_cloned_image_name})",
+                  ecode == 0, locals())
+
+    ## G1: flatten cloned RBD image
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-flatten.sh prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk
+    stdout, stderr, ecode = ceph_rbd_image_flatten(args,
+                                                            server_block_device_mapping['source']['ceph_pool_name'],
+                                                            source_rbd_cloned_image_name)
+    log_or_assert(args,
+                  f"G.10 Source OpenStack VM cloned RBD image flatten successfully ({server_block_device_mapping['source']['ceph_pool_name']}/{source_rbd_cloned_image_name})",
+                  ecode == 0, locals())
+
+    ## G1->G2: copy RBD image to target pool
+    #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-copy.sh prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk cloud-cinder-volumes-prod-brno <g2-rbd-image-name>
+    #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-exists.sh cloud-cinder-volumes-prod-brno <g2-rbd-image-name> # 0
+    stdout, stderr, ecode = ceph_rbd_image_copy(args,
+                                                        server_block_device_mapping['source']['ceph_pool_name'],
+                                                        source_rbd_cloned_image_name,
+                                                        server_block_device_mapping['destination']['ceph_pool_name'],
+                                                        destination_server_rbd_image)
+    log_or_assert(args,
+                  "G.11 Source OpenStack VM RBD image copied G1 -> G2 succesfully" \
+                  f"{server_block_device_mapping['source']['ceph_pool_name']}/{source_rbd_cloned_image_name} -> {server_block_device_mapping['destination']['ceph_pool_name']}/{destination_server_rbd_image}",
+                  ecode == 0, locals())
+    stdout, stderr, ecode = ceph_rbd_image_exists(args,
+                                                        server_block_device_mapping['destination']['ceph_pool_name'],
+                                                        destination_server_rbd_image)
+    log_or_assert(args,
+                  f"G.12 Destination OpenStack VM RBD image exists ({server_block_device_mapping['destination']['ceph_pool_name']}/{destination_server_rbd_image})",
+                  ecode == 0, locals())
+
+    ## G1: delete cloned RBD image
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-delete.sh prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk
+    stdout, stderr, ecode = ceph_rbd_image_delete(args,
+                                                        server_block_device_mapping['source']['ceph_pool_name'],
+                                                        source_rbd_cloned_image_name)
+    log_or_assert(args,
+                  f"G.13 Source OpenStack VM RBD cloned image deletion succeeded ({server_block_device_mapping['source']['ceph_pool_name']}/{source_rbd_cloned_image_name})",
+                  ecode == 0, locals())
+    stdout, stderr, ecode = ceph_rbd_image_exists(args,
+                                                        server_block_device_mapping['source']['ceph_pool_name'],
+                                                        source_rbd_cloned_image_name)
+    log_or_assert(args,
+                  f"G.14 Source OpenStack VM cloned RBD image does not exist anymore ({server_block_device_mapping['source']['ceph_pool_name']}/{source_rbd_cloned_image_name})",
+                  ecode != 0, locals())
+
+    ## G1: remove created snapshot
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-exists.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 0
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-delete.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2
+    #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-exists.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 1
+    stdout, stderr, ecode = ceph_rbd_image_snapshot_exists(args,
+                                                                    server_block_device_mapping['source']['ceph_pool_name'],
+                                                                    source_server_rbd_image,
+                                                                    source_rbd_image_snapshot_name)
+    log_or_assert(args,
+                  "G.15 Source OpenStack VM RBD image snapshot still exists " \
+                  f"{server_block_device_mapping['source']['ceph_pool_name']}/{source_server_rbd_image}@{source_rbd_image_snapshot_name}",
+                  ecode == 0, locals())
+    stdout, stderr, ecode = ceph_rbd_image_snapshot_delete(args,
+                                                                    server_block_device_mapping['source']['ceph_pool_name'],
+                                                                    source_server_rbd_image,
+                                                                    source_rbd_image_snapshot_name)
+    log_or_assert(args,
+                  "G.16 Source OpenStack VM RBD image snapshot deletion succeeeded " \
+                  f"{server_block_device_mapping['source']['ceph_pool_name']}/{source_server_rbd_image}@{source_rbd_image_snapshot_name}",
+                  ecode == 0, locals())
+    stdout, stderr, ecode = ceph_rbd_image_snapshot_exists(args,
+                                                                    server_block_device_mapping['source']['ceph_pool_name'],
+                                                                    source_server_rbd_image,
+                                                                    source_rbd_image_snapshot_name)
+    log_or_assert(args,
+                  "G.17 Source OpenStack VM RBD image snapshot does not exist anymore " \
+                  f"{server_block_device_mapping['source']['ceph_pool_name']}/{source_server_rbd_image}@{source_rbd_image_snapshot_name}",
+                  ecode != 0, locals())
+
+
diff --git a/ci/project-migrator.py b/ci/project-migrator.py
index 852baad..cdb1df4 100755
--- a/ci/project-migrator.py
+++ b/ci/project-migrator.py
@@ -18,6 +18,7 @@ import logging
 import math
 import os
 import os.path
+import pprint
 import sys
 
 import lib
@@ -213,18 +214,8 @@ def main(args):
             # populate i_server_block_device_mappings
             for i_source_server_volume_attachment in i_source_server_volume_attachments:
                 i_server_volume = source_project_conn.block_storage.find_volume(i_source_server_volume_attachment.volume_id)
-                i_server_block_device_mappings.append({'source': {'block_storage_type': 'openstack-volume-ceph-rbd-image',
-                                                                  'volume_attachment_id': i_source_server_volume_attachment.id,
-                                                                  'volume_id': i_server_volume.id,
-                                                                  'ceph_pool_name': args.source_ceph_cinder_pool_name,
-                                                                  'ceph_rbd_image_name': i_server_volume.id},
-                                                       'destination': {'volume_size': i_server_volume.size,
-                                                                       'volume_name': lib.get_migrated_resource_name(args, i_server_volume.name),
-                                                                       'volume_description': i_server_volume.description,
-                                                                       'volume_id': None,
-                                                                       'ceph_pool_name': args.destination_ceph_cinder_pool_name,
-                                                                       'device_name': os.path.basename(i_source_server_volume_attachment.device),
-                                                                       'volume_bootable': i_source_server_root_device_name == i_source_server_volume_attachment.device}})
+                i_server_block_device_mappings.append(lib.get_server_block_device_mapping(args, i_source_server_volume_attachment,
+                                                                                          i_server_volume, i_source_server_root_device_name))
         else:
             args.logger.info("F.22 Source OpenStack server - none of attached volumes is attached as the root partition. Seeking for root partition RBD image")
 
@@ -245,6 +236,7 @@ def main(args):
                 # populate i_server_block_device_mappings
                 ## initial disk
                 i_server_block_device_mappings.append({'source': {'block_storage_type': 'ceph-rbd-image',
+                                                                  'volume_id': i_source_ceph_ephemeral_rbd_image,
                                                                   'ceph_pool_name': args.source_ceph_ephemeral_pool_name,
                                                                   'ceph_rbd_image_name': i_source_ceph_ephemeral_rbd_image,
                                                                   'ceph_rbd_image_size': i_source_ceph_ephemeral_rbd_image_size},
@@ -259,35 +251,20 @@ def main(args):
                 ## other disks attached to VM
                 for i_source_server_volume_attachment in i_source_server_volume_attachments:
                     i_server_volume = source_project_conn.block_storage.find_volume(i_source_server_volume_attachment.volume_id)
-                    i_server_block_device_mappings.append({'source': {'block_storage_type': 'openstack-volume-ceph-rbd-image',
-                                                                      'volume_attachment_id': i_source_server_volume_attachment.id,
-                                                                      'volume_id': i_server_volume.id,
-                                                                      'ceph_pool_name': args.source_ceph_cinder_pool_name,
-                                                                      'ceph_rbd_image_name': i_server_volume.id},
-                                                           'destination': {'volume_size': i_server_volume.size,
-                                                                           'volume_name': lib.get_migrated_resource_name(args, i_server_volume.name),
-                                                                           'volume_description': i_server_volume.description,
-                                                                           'volume_id': None,
-                                                                           'ceph_pool_name': args.destination_ceph_cinder_pool_name,
-                                                                           'device_name': os.path.basename(i_source_server_volume_attachment.device),
-                                                                           'volume_bootable': i_source_server_root_device_name == i_source_server_volume_attachment.device}})
-
-
+                    i_server_block_device_mappings.append(lib.get_server_block_device_mapping(args, i_source_server_volume_attachment,
+                                                                                              i_server_volume, i_source_server_root_device_name))
 
         lib.log_or_assert(args, "F.26 Source OpenStack server - root partition detected",
                       i_server_block_device_mappings and i_server_block_device_mappings[0] and i_server_block_device_mappings[0]['source'])
         lib.log_or_assert(args, "F.27 Destination OpenStack server - root partition details generated",
                       i_server_block_device_mappings and i_server_block_device_mappings[0] and i_server_block_device_mappings[0]['destination'])
 
-        #pprint.pprint(i_server_block_device_mappings)
-        #wait_for_keypress()
-
 
         # volume creation in destination cloud
         for i_destination_server_block_device_mapping in i_server_block_device_mappings:
             i_new_volume_args = {'name': i_destination_server_block_device_mapping['destination']['volume_name'],
                                  'size': i_destination_server_block_device_mapping['destination']['volume_size'],
-                                 'description': f"{i_destination_server_block_device_mapping['destination']['volume_description']}, g1-to-g2-migrated"}
+                                 'description': f"{i_destination_server_block_device_mapping['destination']['volume_description']}, g1-to-g2-migrated(g1-id:{i_destination_server_block_device_mapping['source']['volume_id']})"}
             # TO BE REVISED: this seems to be the only way how to create bootable volume using openstacksdk
             if i_destination_server_block_device_mapping['destination']['volume_bootable']:
                 i_new_volume_args['imageRef'] = destination_image.id
@@ -312,161 +289,13 @@ def main(args):
 
         # volume migration (browse i_server_block_device_mappings)
         for i_server_block_device_mapping in i_server_block_device_mappings:
-            ## G1: detect existing G1 RBD image
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-exists.sh prod-ephemeral-vms 0069e95e-e805-44ff-bab5-872424312ff6
-            i_source_server_rbd_images, i_stderr, i_ecode = lib.ceph_rbd_image_exists(args,
-                                                                                  i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                                  i_server_block_device_mapping['source']['ceph_rbd_image_name'])
-            lib.log_or_assert(args, "F.41 Source OpenStack VM RBD image exists - query succeeded", i_ecode == 0, locals())
-            lib.log_or_assert(args, "F.41 Source OpenStack VM RBD image exists - single image returned",
-                          i_source_server_rbd_images and len(i_source_server_rbd_images) == 1, locals())
-            i_source_server_rbd_image = i_source_server_rbd_images[0]
-
-
-            ## G2: find volume
-            #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-exists.sh cloud-cinder-volumes-prod-brno <g2-rbd-image-name>
-            i_destination_server_rbd_images, i_stderr, i_ecode = lib.ceph_rbd_image_exists(args,
-                                                                                i_server_block_device_mapping['destination']['ceph_pool_name'],
-                                                                                i_server_block_device_mapping['destination']['volume_id'])
-            lib.log_or_assert(args, "F.42 Destination OpenStack VM RBD image exists - query succeeded", i_ecode == 0, locals())
-            lib.log_or_assert(args, "F.42 Destination OpenStack VM RBD image exists - single image returned",
-                          i_destination_server_rbd_images and len(i_destination_server_rbd_images) == 1, locals())
-            i_destination_server_rbd_image = i_destination_server_rbd_images[0]
-
-            ## G1: create RBD image protected snapshot
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-exists.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 1
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-create.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 0
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-exists.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 0
-            i_source_rbd_image_snapshot_name = f"g1-g2-migration-{i_source_server_rbd_image}"
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_snapshot_exists(args,
-                                                                         i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                         i_source_server_rbd_image,
-                                                                         i_source_rbd_image_snapshot_name)
-            lib.log_or_assert(args, "F.43 Source OpenStack VM RBD image has non-colliding snapshot " \
-                                f"({i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_server_rbd_image}@{i_source_rbd_image_snapshot_name})",
-                          i_ecode != 0, locals())
-
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_snapshot_create(args,
-                                                                         i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                         i_source_server_rbd_image,
-                                                                         i_source_rbd_image_snapshot_name)
-            lib.log_or_assert(args, "F.44 Source OpenStack VM RBD image snapshot created " \
-                                f"({i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_server_rbd_image}@{i_source_rbd_image_snapshot_name})",
-                          i_ecode == 0, locals())
-
-
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_snapshot_exists(args,
-                                                                         i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                         i_source_server_rbd_image,
-                                                                         i_source_rbd_image_snapshot_name)
-            lib.log_or_assert(args, "F.45 Source OpenStack VM RBD image snapshot exists " \
-                                f"({i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_server_rbd_image}@{i_source_rbd_image_snapshot_name})",
-                          i_ecode == 0, locals())
-
-            ## G2: delete RBD image
-            #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-delete.sh cloud-cinder-volumes-prod-brno <g2-rbd-image-name>
-            ## G2: confirm volume is deleted
-            #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-exists.sh cloud-cinder-volumes-prod-brno <g2-rbd-image-name> # 1
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_delete(args,
-                                                                i_server_block_device_mapping['destination']['ceph_pool_name'],
-                                                                i_destination_server_rbd_image)
-            lib.log_or_assert(args, f"F.46 Destination OpenStack VM RBD image deletion succeeded ({i_server_block_device_mapping['destination']['ceph_pool_name']}/{i_destination_server_rbd_image})",
-                          i_ecode == 0, locals())
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_exists(args,
-                                                                i_server_block_device_mapping['destination']['ceph_pool_name'],
-                                                                i_destination_server_rbd_image)
-            lib.log_or_assert(args, f"F.47 Destination OpenStack VM RBD image does not exist ({i_server_block_device_mapping['destination']['ceph_pool_name']}/{i_destination_server_rbd_image})",
-                          i_ecode != 0, locals())
-
-
-            ## G1: clone from snapshot
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-clone.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-exists.sh prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk
-            i_source_rbd_cloned_image_name = f"g1-g2-migration-{i_source_server_rbd_image}"
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_clone(args,
-                                                               i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                               i_source_server_rbd_image,
-                                                               i_source_rbd_image_snapshot_name,
-                                                               i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                               i_source_rbd_cloned_image_name)
-            lib.log_or_assert(args, "F.48 Source OpenStack VM RBD image cloned succesfully " \
-                          f"({i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_server_rbd_image}@{i_source_rbd_image_snapshot_name} -> {i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_rbd_cloned_image_name})",
-                          i_ecode == 0, locals())
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_exists(args,
-                                                                i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                i_source_rbd_cloned_image_name)
-            lib.log_or_assert(args, f"F.49 Source OpenStack VM cloned RBD image exists ({i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_rbd_cloned_image_name})",
-                          i_ecode == 0, locals())
-
-            ## G1: flatten cloned RBD image
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-flatten.sh prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_flatten(args,
-                                                                 i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                 i_source_rbd_cloned_image_name)
-            lib.log_or_assert(args, f"F.50 Source OpenStack VM cloned RBD image flatten successfully ({i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_rbd_cloned_image_name})",
-                          i_ecode == 0, locals())
-
-            ## G1->G2: copy RBD image to target pool
-            #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-copy.sh prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk cloud-cinder-volumes-prod-brno <g2-rbd-image-name>
-            #CEPH_USER=client.migrator ~/migrator/ceph-rbd-image-exists.sh cloud-cinder-volumes-prod-brno <g2-rbd-image-name> # 0
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_copy(args,
-                                                              i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                              i_source_rbd_cloned_image_name,
-                                                              i_server_block_device_mapping['destination']['ceph_pool_name'],
-                                                              i_destination_server_rbd_image)
-            lib.log_or_assert(args, "F.51 Source OpenStack VM RBD image copied G1 -> G2 succesfully" \
-                                f"{i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_rbd_cloned_image_name} -> {i_server_block_device_mapping['destination']['ceph_pool_name']}/{i_destination_server_rbd_image}",
-                          i_ecode == 0, locals())
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_exists(args,
-                                                                i_server_block_device_mapping['destination']['ceph_pool_name'],
-                                                                i_destination_server_rbd_image)
-            lib.log_or_assert(args, f"F.52 Destination OpenStack VM RBD image exists ({i_server_block_device_mapping['destination']['ceph_pool_name']}/{i_destination_server_rbd_image})",
-                          i_ecode == 0, locals())
-
-            ## G1: delete cloned RBD image
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-delete.sh prod-ephemeral-vms migrated-006e230e-df45-4f33-879b-19eada244489_disk
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_delete(args,
-                                                                i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                i_source_rbd_cloned_image_name)
-            lib.log_or_assert(args, f"F.53 Source OpenStack VM RBD cloned image deletion succeeded ({i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_rbd_cloned_image_name})",
-                          i_ecode == 0, locals())
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_exists(args,
-                                                                i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                i_source_rbd_cloned_image_name)
-            lib.log_or_assert(args, f"F.54 Source OpenStack VM cloned RBD image does not exist anymore ({i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_rbd_cloned_image_name})",
-                          i_ecode != 0, locals())
-
-            ## G1: remove created snapshot
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-exists.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 0
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-delete.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2
-            #CEPH_USER=client.cinder ~/migrator/ceph-rbd-image-snapshot-exists.sh prod-ephemeral-vms 006e230e-df45-4f33-879b-19eada244489_disk migration-snap2 # 1
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_snapshot_exists(args,
-                                                                         i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                         i_source_server_rbd_image,
-                                                                         i_source_rbd_image_snapshot_name)
-            lib.log_or_assert(args, "F.55 Source OpenStack VM RBD image snapshot still exists " \
-                                f"{i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_server_rbd_image}@{i_source_rbd_image_snapshot_name}",
-                          i_ecode == 0, locals())
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_snapshot_delete(args,
-                                                                         i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                         i_source_server_rbd_image,
-                                                                         i_source_rbd_image_snapshot_name)
-            lib.log_or_assert(args, "F.56 Source OpenStack VM RBD image snapshot deletion succeeeded " \
-                                f"{i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_server_rbd_image}@{i_source_rbd_image_snapshot_name}",
-                          i_ecode == 0, locals())
-            i_stdout, i_stderr, i_ecode = lib.ceph_rbd_image_snapshot_exists(args,
-                                                                         i_server_block_device_mapping['source']['ceph_pool_name'],
-                                                                         i_source_server_rbd_image,
-                                                                         i_source_rbd_image_snapshot_name)
-            lib.log_or_assert(args, "F.57 Source OpenStack VM RBD image snapshot does not exist anymore " \
-                                f"{i_server_block_device_mapping['source']['ceph_pool_name']}/{i_source_server_rbd_image}@{i_source_rbd_image_snapshot_name}",
-                          i_ecode != 0, locals())
+            lib.migrate_rbd_image(args, i_server_block_device_mapping)
 
         # start server in source cloud, wait for back being 'ACTIVE'
         if i_source_server_detail.status != source_project_conn.compute.find_server(i_source_server.id).status:
             if i_source_server_detail.status == 'ACTIVE':
                 source_project_conn.compute.start_server(i_source_server_detail)
-                lib.log_or_assert(args, "F.49 Source OpenStack VM server started back",
+                lib.log_or_assert(args, "F.34 Source OpenStack VM server started back",
                               lib.wait_for_ostack_server_status(source_project_conn, i_source_server.id, 'ACTIVE') == "ACTIVE",
                               locals())
 
@@ -484,16 +313,16 @@ def main(args):
                                      'boot_volume': i_server_block_device_mappings[0]['destination']['volume_id'],
                                      'key_name': i_destination_server_keypair["name"],
                                      'networks': [ {'uuid': i_network.id} for i_network in i_destination_server_networks ]}
-        lib.log_or_assert(args, "F.60 Destination OpenStack server arguments are generated with valid block-device-mapping",
+        lib.log_or_assert(args, "F.35 Destination OpenStack server arguments are generated with valid block-device-mapping",
                       i_destination_server_args['block_device_mapping_v2'], locals())
-        lib.log_or_assert(args, "F.60 Destination OpenStack server arguments are generated with valid network configuration",
+        lib.log_or_assert(args, "F.36 Destination OpenStack server arguments are generated with valid network configuration",
                       i_destination_server_args['networks'], locals())
 
         #pprint.pprint(i_destination_server_args)
         i_destination_server = destination_project_conn.compute.create_server(**i_destination_server_args)
-        lib.log_or_assert(args, "F.61 Destination OpenStack server is created", i_destination_server, locals())
+        lib.log_or_assert(args, "F.37 Destination OpenStack server is created", i_destination_server, locals())
         i_destination_server = destination_project_conn.compute.wait_for_server(i_destination_server)
-        lib.log_or_assert(args, "F.62 Destination OpenStack server got ACTIVE",
+        lib.log_or_assert(args, "F.38 Destination OpenStack server got ACTIVE",
                       i_destination_server.status == 'ACTIVE', locals())
 
         # add security groups to the destination server (if missing)
@@ -503,12 +332,42 @@ def main(args):
         if i_source_server_has_fip:
             # add FIP as source VM has it
             i_destination_server_fip = destination_project_conn.network.create_ip(floating_network_id=destination_fip_network.id)
-            lib.log_or_assert(args, "F.63 Destination OpenStack server FIP is created", i_destination_server_fip, locals())
+            lib.log_or_assert(args, "F.39 Destination OpenStack server FIP is created", i_destination_server_fip, locals())
             i_destination_server_port = lib.get_server_floating_ip_port(destination_project_conn, i_destination_server)
-            lib.log_or_assert(args, "F.64 Destination OpenStack server FIP port is detected", i_destination_server_port, locals())
+            lib.log_or_assert(args, "F.40 Destination OpenStack server FIP port is detected", i_destination_server_port, locals())
             destination_project_conn.network.add_ip_to_port(i_destination_server_port, i_destination_server_fip)
 
-        args.logger.info(f"F.66 Source OpenStack server name:{i_source_server_detail.name} migrated into destination one name:{i_destination_server.name} id:{i_destination_server.id}")
+        args.logger.info(f"F.41 Source OpenStack server name:{i_source_server_detail.name} migrated into destination one name:{i_destination_server.name} id:{i_destination_server.id}")
+
+    if args.explicit_volume_names:
+        for i_source_volume_name in args.explicit_volume_names:
+            i_source_volume = source_project_conn.block_storage.find_volume(i_source_volume_name)
+            if not i_source_volume:
+                args.logger.info(f"H.1 Source volume migration skipped as does not exist (name:{i_source_volume_name})")
+                continue
+            if i_source_volume.status != 'available':
+                args.logger.info(f"H.2 Source volume migration skipped as it is not in state available (name:{i_source_volume_name}, state:{i_source_volume.status}). " \
+                                "Note in-use volumes are being migrated in VM server migration part.")
+                continue
+
+            i_dst_volume = destination_project_conn.block_storage.create_volume(name=lib.get_migrated_resource_name(args, i_source_volume.name),
+                                                                                size=i_source_volume.size,
+                                                                                description=f"{i_source_volume.description}, g1-to-g2-migrated(g1-id:{i_source_volume.id})")
+            lib.log_or_assert(args,
+                            f"H.3 Destination OpenStack volume created (name:{i_dst_volume.name}, id:{i_dst_volume.id})", i_dst_volume)
+            i_dst_volume_status = lib.wait_for_ostack_volume_status(destination_project_conn, i_dst_volume.id, 'available')
+            lib.log_or_assert(args,
+                            f"H.4 Destination OpenStack volume available (name:{i_dst_volume.name}, id:{i_dst_volume.id})",
+                            i_dst_volume_status == 'available')
+            i_volume_mapping = {'source':      {'ceph_pool_name': args.source_ceph_cinder_pool_name,
+                                                'ceph_rbd_image_name': i_source_volume.id},
+                                'destination': {'ceph_pool_name': args.destination_ceph_cinder_pool_name,
+                                                'volume_id': i_dst_volume.id}}
+            lib.migrate_rbd_image(args, i_volume_mapping)
+            i_dst_volume_detail = destination_project_conn.block_storage.find_volume(i_dst_volume.id)
+            lib.log_or_assert(args,
+                            f"H.5 Destination OpenStack volume available (name:{i_dst_volume_detail.name}, id:{i_dst_volume_detail.id})",
+                            i_dst_volume_detail.status == 'available')
 
 
 # main() call (argument parsing)
@@ -551,7 +410,7 @@ if __name__ == "__main__":
     AP.add_argument('--explicit-server-names', default=None, required=False,
                     help='(Optional) List of explicit server names or IDs to be migrated. Delimiter comma or space.')
     AP.add_argument('--explicit-volume-names', default=None, required=False,
-                    help='(Optional) List of explicit volume names or IDs to be migrated. Delimiter comma or space.')
+                    help='(Optional) List of explicit volume (names or) IDs to be migrated. Delimiter comma or space.')
     AP.add_argument('--migrate-also-inactive-servers', default=False, required=False, action='store_true',
                     help='(Optional) Migrate also inactive servers (i.e. PAUSED/SHUTOFF).')
 
@@ -567,4 +426,5 @@ if __name__ == "__main__":
     ARGS = AP.parse_args()
     ARGS.logger = logging.getLogger("project-migrator")
     ARGS.explicit_server_names = lib.normalize_servers(ARGS.explicit_server_names)
+    ARGS.explicit_volume_names = lib.normalize_servers(ARGS.explicit_volume_names)
     sys.exit(main(ARGS))
-- 
GitLab