Browse Source

Adds clone_disks feature

Alessandro Pilotti 9 years ago
parent
commit
0407c96051

+ 2 - 1
coriolis/api/v1/migrations.py

@@ -72,10 +72,11 @@ class MigrationController(api_wsgi.Controller):
 
         replica_id = migration_body.get("replica_id")
         if replica_id:
+            clone_disks = migration_body.get("clone_disks", True)
             force = migration_body.get("force", False)
 
             migration = self._migration_api.deploy_replica_instances(
-                context, replica_id, force)
+                context, replica_id, clone_disks, force)
         else:
             origin, destination, instances = self._validate_migration_input(
                 migration_body)

+ 3 - 2
coriolis/conductor/rpc/client.py

@@ -76,10 +76,11 @@ class ConductorClient(object):
             ctxt, 'migrate_instances', origin=origin, destination=destination,
             instances=instances)
 
-    def deploy_replica_instances(self, ctxt, replica_id, force=False):
+    def deploy_replica_instances(self, ctxt, replica_id, clone_disks=False,
+                                 force=False):
         return self._client.call(
             ctxt, 'deploy_replica_instances', replica_id=replica_id,
-            force=force)
+            clone_disks=clone_disks, force=force)
 
     def delete_migration(self, ctxt, migration_id):
         self._client.call(

+ 17 - 9
coriolis/conductor/rpc/server.py

@@ -297,7 +297,7 @@ class ConductorServerEndpoint(object):
                 "to be migrated")
 
     @replica_synchronized
-    def deploy_replica_instances(self, ctxt, replica_id, force):
+    def deploy_replica_instances(self, ctxt, replica_id, clone_disks, force):
         replica = self._get_replica(ctxt, replica_id)
         self._check_replica_running_executions(ctxt, replica)
         self._check_valid_replica_tasks_execution(replica, force)
@@ -320,6 +320,9 @@ class ConductorServerEndpoint(object):
         migration.replica = replica
         migration.info = replica.info
 
+        for instance in instances:
+            migration.info[instance]["clone_disks"] = clone_disks
+
         execution = models.TasksExecution()
         migration.executions = [execution]
         execution.status = constants.EXECUTION_STATUS_RUNNING
@@ -336,12 +339,14 @@ class ConductorServerEndpoint(object):
 
             self._create_task(
                 instance, constants.TASK_TYPE_DELETE_REPLICA_DISK_SNAPSHOTS,
-                execution, [deploy_replica_task.id])
+                execution, [deploy_replica_task.id],
+                on_error=clone_disks)
 
-            self._create_task(
-                instance,
-                constants.TASK_TYPE_RESTORE_REPLICA_DISK_SNAPSHOTS,
-                execution, on_error=True)
+            if not clone_disks:
+                self._create_task(
+                    instance,
+                    constants.TASK_TYPE_RESTORE_REPLICA_DISK_SNAPSHOTS,
+                    execution, on_error=True)
 
         db_api.add_migration(ctxt, migration)
         LOG.info("Migration created: %s", migration.id)
@@ -498,9 +503,12 @@ class ConductorServerEndpoint(object):
             if volumes_info:
                 updated_task_info = {"volumes_info": volumes_info}
         elif task_type == constants.TASK_TYPE_DELETE_REPLICA_DISK_SNAPSHOTS:
-            # The migration completed. If the replica is executed again,
-            # new volumes need to be deployed in place of the migrated ones.
-            updated_task_info = {"volumes_info": None}
+
+            if not task_info.get("clone_disks"):
+                # The migration completed. If the replica is executed again,
+                # new volumes need to be deployed in place of the migrated
+                # ones.
+                updated_task_info = {"volumes_info": None}
 
         if updated_task_info:
             self._update_replica_volumes_info(

+ 3 - 2
coriolis/migrations/api.py

@@ -12,9 +12,10 @@ class API(object):
         return self._rpc_client.migrate_instances(
             ctxt, origin, destination, instances)
 
-    def deploy_replica_instances(self, ctxt, replica_id, force=False):
+    def deploy_replica_instances(self, ctxt, replica_id, clone_disks=False,
+                                 force=False):
         return self._rpc_client.deploy_replica_instances(
-            ctxt, replica_id, force)
+            ctxt, replica_id, clone_disks, force)
 
     def delete(self, ctxt, migration_id):
         self._rpc_client.delete_migration(ctxt, migration_id)

+ 1 - 1
coriolis/providers/base.py

@@ -61,7 +61,7 @@ class BaseReplicaImportProvider(BaseImportProvider):
     @abc.abstractmethod
     def deploy_replica_instance(self, ctxt, connection_info,
                                 target_environment, instance_name, export_info,
-                                volumes_info):
+                                volumes_info, clone_disks):
         pass
 
     @abc.abstractmethod

+ 26 - 6
coriolis/providers/openstack/__init__.py

@@ -676,8 +676,23 @@ class ImportProvider(base.BaseReplicaImportProvider):
             if not volume.bootable or volume.bootable == 'false':
                 cinder.volumes.set_bootable(volume, True)
 
+    def _create_volumes_from_replica_snapshots(self, cinder, volumes_info):
+        volumes = []
+        for volume_info in volumes_info:
+            snapshot_id = volume_info["volume_snapshot_id"]
+            volume_name = _get_unique_name()
+
+            self._event_manager.progress_update(
+                "Creating Cinder volume from snapshot")
+
+            volume = _create_volume(
+                cinder, None, volume_name, snapshot_id=snapshot_id)
+            volumes.append(volume)
+        return volumes
+
     def _deploy_instance(self, ctxt, connection_info, target_environment,
-                         instance_name, export_info, volumes_info=None):
+                         instance_name, export_info, volumes_info=None,
+                         clone_disks=False):
         session = keystone.create_keystone_session(ctxt, connection_info)
 
         glance_api_version = connection_info.get("image_api_version",
@@ -704,8 +719,12 @@ class ImportProvider(base.BaseReplicaImportProvider):
                 images, volumes = self._create_images_and_volumes(
                     glance, nova, cinder, config, disks_info)
             else:
-                # Replica
-                volumes = self._get_replica_volumes(cinder, volumes_info)
+                # Migration from replica
+                if not clone_disks:
+                    volumes = self._get_replica_volumes(cinder, volumes_info)
+                else:
+                    volumes = self._create_volumes_from_replica_snapshots(
+                        cinder, volumes_info)
 
             migr_resources = self._deploy_migration_resources(
                 nova, glance, neutron, os_type, config.migr_image_name,
@@ -759,7 +778,7 @@ class ImportProvider(base.BaseReplicaImportProvider):
                 nova, config.flavor_name, instance_name,
                 config.keypair_name, ports, volumes)
         except:
-            if not volumes_info:
+            if not volumes_info or clone_disks:
                 # Don't remove replica volumes
                 self._event_manager.progress_update("Deleting volumes")
                 for volume in volumes:
@@ -830,9 +849,10 @@ class ImportProvider(base.BaseReplicaImportProvider):
 
     def deploy_replica_instance(self, ctxt, connection_info,
                                 target_environment, instance_name, export_info,
-                                volumes_info):
+                                volumes_info, clone_disks):
         self._deploy_instance(ctxt, connection_info, target_environment,
-                              instance_name, export_info, volumes_info)
+                              instance_name, export_info, volumes_info,
+                              clone_disks)
 
     def _update_existing_disk_volumes(self, cinder, disks_info, volumes_info):
         for disk_info in disks_info:

+ 3 - 1
coriolis/tasks/replica_tasks.py

@@ -236,10 +236,12 @@ class DeployReplicaInstanceTask(base.TaskRunner):
         connection_info = base.get_connection_info(ctxt, destination)
 
         volumes_info = _get_volumes_info(task_info)
+        clone_disks = task_info.get("clone_disks", True)
+        LOG.debug("Clone disks: %s", clone_disks)
 
         provider.deploy_replica_instance(
             ctxt, connection_info, target_environment, instance,
-            export_info, volumes_info)
+            export_info, volumes_info, clone_disks)
 
         return task_info