|
@@ -16,7 +16,7 @@ LOG = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_volumes_info(task_info):
|
|
def _get_volumes_info(task_info):
|
|
|
- volumes_info = task_info.get("volumes_info")
|
|
|
|
|
|
|
+ volumes_info = task_info.get("volumes_info", [])
|
|
|
if not volumes_info:
|
|
if not volumes_info:
|
|
|
raise exception.InvalidActionTasksExecutionState(
|
|
raise exception.InvalidActionTasksExecutionState(
|
|
|
"No volumes information present")
|
|
"No volumes information present")
|
|
@@ -37,21 +37,21 @@ def _check_ensure_volumes_info_ordering(export_info, volumes_info):
|
|
|
matching_volumes = [
|
|
matching_volumes = [
|
|
|
vol for vol in volumes_info if vol['disk_id'] == disk_id]
|
|
vol for vol in volumes_info if vol['disk_id'] == disk_id]
|
|
|
if not matching_volumes:
|
|
if not matching_volumes:
|
|
|
- raise exception.CoriolisException(
|
|
|
|
|
|
|
+ raise exception.InvalidActionTasksExecutionState(
|
|
|
"Could not find source disk '%s' (ID '%s') in Replica "
|
|
"Could not find source disk '%s' (ID '%s') in Replica "
|
|
|
"volumes info: %s" % (disk, disk_id, volumes_info))
|
|
"volumes info: %s" % (disk, disk_id, volumes_info))
|
|
|
elif len(matching_volumes) > 1:
|
|
elif len(matching_volumes) > 1:
|
|
|
- raise exception.CoriolisException(
|
|
|
|
|
|
|
+ raise exception.InvalidActionTasksExecutionState(
|
|
|
"Multiple disks with ID '%s' foind in Replica "
|
|
"Multiple disks with ID '%s' foind in Replica "
|
|
|
"volumes info: %s" % (disk_id, volumes_info))
|
|
"volumes info: %s" % (disk_id, volumes_info))
|
|
|
|
|
|
|
|
ordered_volumes_info.append(matching_volumes[0])
|
|
ordered_volumes_info.append(matching_volumes[0])
|
|
|
|
|
|
|
|
vol_info_cpy = utils.filter_chunking_info_for_task(
|
|
vol_info_cpy = utils.filter_chunking_info_for_task(
|
|
|
- {"volumes_info": volumes_info}).get("volumes_info")
|
|
|
|
|
|
|
+ {"volumes_info": volumes_info}).get("volumes_info", [])
|
|
|
|
|
|
|
|
ordered_vol_info_cpy = utils.filter_chunking_info_for_task(
|
|
ordered_vol_info_cpy = utils.filter_chunking_info_for_task(
|
|
|
- {"volumes_info": ordered_volumes_info}).get("volumes_info")
|
|
|
|
|
|
|
+ {"volumes_info": ordered_volumes_info}).get("volumes_info", [])
|
|
|
|
|
|
|
|
LOG.debug(
|
|
LOG.debug(
|
|
|
"volumes_info returned by provider for instance "
|
|
"volumes_info returned by provider for instance "
|
|
@@ -64,42 +64,74 @@ def _check_ensure_volumes_info_ordering(export_info, volumes_info):
|
|
|
|
|
|
|
|
|
|
|
|
|
class GetInstanceInfoTask(base.TaskRunner):
|
|
class GetInstanceInfoTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+ """ Task which gathers the export info for a VM. """
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["source_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["export_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
|
connection_info = base.get_connection_info(ctxt, origin)
|
|
connection_info = base.get_connection_info(ctxt, origin)
|
|
|
|
|
|
|
|
- source_environment = origin.get('source_environment') or {}
|
|
|
|
|
|
|
+ source_environment = task_info['source_environment']
|
|
|
export_info = provider.get_replica_instance_info(
|
|
export_info = provider.get_replica_instance_info(
|
|
|
ctxt, connection_info, source_environment, instance)
|
|
ctxt, connection_info, source_environment, instance)
|
|
|
|
|
|
|
|
# Validate the output
|
|
# Validate the output
|
|
|
schemas.validate_value(
|
|
schemas.validate_value(
|
|
|
export_info, schemas.CORIOLIS_VM_EXPORT_INFO_SCHEMA)
|
|
export_info, schemas.CORIOLIS_VM_EXPORT_INFO_SCHEMA)
|
|
|
- task_info["export_info"] = export_info
|
|
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ 'export_info': export_info}
|
|
|
|
|
|
|
|
|
|
|
|
|
class ShutdownInstanceTask(base.TaskRunner):
|
|
class ShutdownInstanceTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+ """ Task which shuts down a VM. """
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["source_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return []
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
|
connection_info = base.get_connection_info(ctxt, origin)
|
|
connection_info = base.get_connection_info(ctxt, origin)
|
|
|
|
|
|
|
|
- source_environment = origin.get('source_environment') or {}
|
|
|
|
|
|
|
+ source_environment = task_info['source_environment']
|
|
|
provider.shutdown_instance(ctxt, connection_info, source_environment,
|
|
provider.shutdown_instance(ctxt, connection_info, source_environment,
|
|
|
instance)
|
|
instance)
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {}
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReplicateDisksTask(base.TaskRunner):
|
|
class ReplicateDisksTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return [
|
|
|
|
|
+ "export_info", "volumes_info", "source_environment",
|
|
|
|
|
+ "source_resources",
|
|
|
|
|
+ "source_resources_connection_info",
|
|
|
|
|
+ "target_resources_connection_info"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
event_handler):
|
|
event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
@@ -112,7 +144,7 @@ class ReplicateDisksTask(base.TaskRunner):
|
|
|
{"volumes_info": volumes_info},
|
|
{"volumes_info": volumes_info},
|
|
|
schemas.CORIOLIS_DISK_SYNC_RESOURCES_INFO_SCHEMA)
|
|
schemas.CORIOLIS_DISK_SYNC_RESOURCES_INFO_SCHEMA)
|
|
|
|
|
|
|
|
- migr_source_conn_info = task_info["migr_source_connection_info"]
|
|
|
|
|
|
|
+ migr_source_conn_info = task_info["source_resources_connection_info"]
|
|
|
if migr_source_conn_info:
|
|
if migr_source_conn_info:
|
|
|
schemas.validate_value(
|
|
schemas.validate_value(
|
|
|
migr_source_conn_info,
|
|
migr_source_conn_info,
|
|
@@ -120,11 +152,17 @@ class ReplicateDisksTask(base.TaskRunner):
|
|
|
migr_source_conn_info = base.unmarshal_migr_conn_info(
|
|
migr_source_conn_info = base.unmarshal_migr_conn_info(
|
|
|
migr_source_conn_info)
|
|
migr_source_conn_info)
|
|
|
|
|
|
|
|
- migr_target_conn_info = task_info["migr_target_connection_info"]
|
|
|
|
|
|
|
+ migr_target_conn_info = task_info["target_resources_connection_info"]
|
|
|
incremental = task_info.get("incremental", True)
|
|
incremental = task_info.get("incremental", True)
|
|
|
|
|
|
|
|
- source_environment = origin.get('source_environment') or {}
|
|
|
|
|
|
|
+ source_environment = task_info['source_environment']
|
|
|
|
|
|
|
|
|
|
+ # TODO(aznashwan): in order to facilitate parallelized setups,
|
|
|
|
|
+ # we should modify the replicate_disks provider method to allow for the
|
|
|
|
|
+ # passing in of source_resources info as well.
|
|
|
|
|
+ # This could be used to for example pass in the ID/info of a
|
|
|
|
|
+ # pre-created source worker VM which can then be (re)used by the
|
|
|
|
|
+ # Replicate disks task during PMR.
|
|
|
volumes_info = provider.replicate_disks(
|
|
volumes_info = provider.replicate_disks(
|
|
|
ctxt, connection_info, source_environment, instance,
|
|
ctxt, connection_info, source_environment, instance,
|
|
|
migr_source_conn_info, migr_target_conn_info, volumes_info,
|
|
migr_source_conn_info, migr_target_conn_info, volumes_info,
|
|
@@ -135,15 +173,24 @@ class ReplicateDisksTask(base.TaskRunner):
|
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
|
export_info, volumes_info)
|
|
export_info, volumes_info)
|
|
|
|
|
|
|
|
- task_info["volumes_info"] = volumes_info
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ 'volumes_info': volumes_info}
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeployReplicaDisksTask(base.TaskRunner):
|
|
class DeployReplicaDisksTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return [
|
|
|
|
|
+ "export_info", "volumes_info", "target_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
event_handler):
|
|
event_handler):
|
|
|
- target_environment = destination.get("target_environment") or {}
|
|
|
|
|
|
|
+ target_environment = task_info['target_environment']
|
|
|
export_info = task_info["export_info"]
|
|
export_info = task_info["export_info"]
|
|
|
|
|
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
@@ -152,10 +199,6 @@ class DeployReplicaDisksTask(base.TaskRunner):
|
|
|
connection_info = base.get_connection_info(ctxt, destination)
|
|
connection_info = base.get_connection_info(ctxt, destination)
|
|
|
|
|
|
|
|
volumes_info = task_info.get("volumes_info", [])
|
|
volumes_info = task_info.get("volumes_info", [])
|
|
|
- if volumes_info is None:
|
|
|
|
|
- # In case Replica disks were deleted:
|
|
|
|
|
- volumes_info = []
|
|
|
|
|
-
|
|
|
|
|
volumes_info = provider.deploy_replica_disks(
|
|
volumes_info = provider.deploy_replica_disks(
|
|
|
ctxt, connection_info, target_environment, instance, export_info,
|
|
ctxt, connection_info, target_environment, instance, export_info,
|
|
|
volumes_info)
|
|
volumes_info)
|
|
@@ -165,18 +208,27 @@ class DeployReplicaDisksTask(base.TaskRunner):
|
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
|
export_info, volumes_info)
|
|
export_info, volumes_info)
|
|
|
|
|
|
|
|
- task_info["volumes_info"] = volumes_info
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ 'volumes_info': volumes_info}
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeleteReplicaDisksTask(base.TaskRunner):
|
|
class DeleteReplicaDisksTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return [
|
|
|
|
|
+ "volumes_info", "target_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
event_handler):
|
|
event_handler):
|
|
|
if not task_info.get("volumes_info"):
|
|
if not task_info.get("volumes_info"):
|
|
|
LOG.debug(
|
|
LOG.debug(
|
|
|
"No volumes_info present. Skipping disk deletion.")
|
|
"No volumes_info present. Skipping disk deletion.")
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {'volumes_info': []}
|
|
|
|
|
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
@@ -185,74 +237,123 @@ class DeleteReplicaDisksTask(base.TaskRunner):
|
|
|
|
|
|
|
|
volumes_info = _get_volumes_info(task_info)
|
|
volumes_info = _get_volumes_info(task_info)
|
|
|
|
|
|
|
|
|
|
+ # TODO (aznashwan): add target_env options to `delete_replica_disks`:
|
|
|
volumes_info = provider.delete_replica_disks(
|
|
volumes_info = provider.delete_replica_disks(
|
|
|
ctxt, connection_info, volumes_info)
|
|
ctxt, connection_info, volumes_info)
|
|
|
if volumes_info:
|
|
if volumes_info:
|
|
|
LOG.warn(
|
|
LOG.warn(
|
|
|
"'volumes_info' should have been void after disk "
|
|
"'volumes_info' should have been void after disk "
|
|
|
- "deletion: %s" % volumes_info)
|
|
|
|
|
-
|
|
|
|
|
- task_info["volumes_info"] = []
|
|
|
|
|
|
|
+ "deletion task but it is: %s" % volumes_info)
|
|
|
|
|
+ elif volumes_info is None:
|
|
|
|
|
+ volumes_info = []
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ 'volumes_info': volumes_info}
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeployReplicaSourceResourcesTask(base.TaskRunner):
|
|
class DeployReplicaSourceResourcesTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["source_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["source_resources", "source_resources_connection_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
|
connection_info = base.get_connection_info(ctxt, origin)
|
|
connection_info = base.get_connection_info(ctxt, origin)
|
|
|
|
|
|
|
|
- source_environment = origin.get('source_environment') or {}
|
|
|
|
|
|
|
+ source_environment = task_info['source_environment'] or {}
|
|
|
replica_resources_info = provider.deploy_replica_source_resources(
|
|
replica_resources_info = provider.deploy_replica_source_resources(
|
|
|
ctxt, connection_info, source_environment)
|
|
ctxt, connection_info, source_environment)
|
|
|
|
|
|
|
|
- task_info["migr_source_resources"] = replica_resources_info[
|
|
|
|
|
- "migr_resources"]
|
|
|
|
|
- migr_connection_info = replica_resources_info.get("connection_info")
|
|
|
|
|
- if migr_connection_info:
|
|
|
|
|
- migr_connection_info = base.marshal_migr_conn_info(
|
|
|
|
|
- migr_connection_info)
|
|
|
|
|
- schemas.validate_value(
|
|
|
|
|
- migr_connection_info,
|
|
|
|
|
- schemas.CORIOLIS_DISK_SYNC_RESOURCES_CONN_INFO_SCHEMA,
|
|
|
|
|
- # NOTE: we avoid raising so that the cleanup task
|
|
|
|
|
- # can [try] to deal with the temporary resources.
|
|
|
|
|
- raise_on_error=False)
|
|
|
|
|
-
|
|
|
|
|
- task_info["migr_source_connection_info"] = migr_connection_info
|
|
|
|
|
|
|
+ migr_connection_info = replica_resources_info.get(
|
|
|
|
|
+ "connection_info", {})
|
|
|
|
|
+ if 'connection_info' not in replica_resources_info:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Replica source provider for '%s' did NOT return any "
|
|
|
|
|
+ "'connection_info'. Defaulting to '%s'",
|
|
|
|
|
+ origin["type"], migr_connection_info)
|
|
|
|
|
+ else:
|
|
|
|
|
+ migr_connection_info = replica_resources_info['connection_info']
|
|
|
|
|
+ if migr_connection_info:
|
|
|
|
|
+ migr_connection_info = base.marshal_migr_conn_info(
|
|
|
|
|
+ migr_connection_info)
|
|
|
|
|
+ schemas.validate_value(
|
|
|
|
|
+ migr_connection_info,
|
|
|
|
|
+ schemas.CORIOLIS_DISK_SYNC_RESOURCES_CONN_INFO_SCHEMA,
|
|
|
|
|
+ # NOTE: we avoid raising so that the cleanup task
|
|
|
|
|
+ # can [try] to deal with the temporary resources.
|
|
|
|
|
+ raise_on_error=False)
|
|
|
|
|
+ else:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Replica source provider for '%s' returned empty "
|
|
|
|
|
+ "'connection_info' in source resources deployment: %s",
|
|
|
|
|
+ origin["type"], migr_connection_info)
|
|
|
|
|
+
|
|
|
|
|
+ migr_resources = {}
|
|
|
|
|
+ if 'migr_resources' not in replica_resources_info:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Replica source provider for '%s' did NOT return any "
|
|
|
|
|
+ "'migr_resources'. Defaulting to %s",
|
|
|
|
|
+ origin["type"], migr_resources)
|
|
|
|
|
+ else:
|
|
|
|
|
+ migr_resources = replica_resources_info['migr_resources']
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "source_resources": migr_resources,
|
|
|
|
|
+ "source_resources_connection_info": migr_connection_info}
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeleteReplicaSourceResourcesTask(base.TaskRunner):
|
|
class DeleteReplicaSourceResourcesTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["source_environment", "source_resources"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["source_resources", "source_resources_connection_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
|
connection_info = base.get_connection_info(ctxt, origin)
|
|
connection_info = base.get_connection_info(ctxt, origin)
|
|
|
|
|
|
|
|
- migr_resources = task_info.get("migr_source_resources")
|
|
|
|
|
-
|
|
|
|
|
- source_environment = origin.get("source_environment", {})
|
|
|
|
|
|
|
+ migr_resources = task_info["source_resources"]
|
|
|
|
|
+ source_environment = origin["source_environment"]
|
|
|
|
|
|
|
|
if migr_resources:
|
|
if migr_resources:
|
|
|
provider.delete_replica_source_resources(
|
|
provider.delete_replica_source_resources(
|
|
|
ctxt, connection_info, source_environment, migr_resources)
|
|
ctxt, connection_info, source_environment, migr_resources)
|
|
|
|
|
|
|
|
- task_info["migr_source_resources"] = None
|
|
|
|
|
- task_info["migr_source_connection_info"] = None
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "source_resources": None,
|
|
|
|
|
+ "source_resources_connection_info": None}
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeployReplicaTargetResourcesTask(base.TaskRunner):
|
|
class DeployReplicaTargetResourcesTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
- target_environment = destination.get("target_environment") or {}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["export_info", "volumes_info", "target_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return [
|
|
|
|
|
+ "volumes_info", "target_resources",
|
|
|
|
|
+ "target_resources_connection_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
|
|
+ target_environment = task_info["target_environment"]
|
|
|
export_info = task_info['export_info']
|
|
export_info = task_info['export_info']
|
|
|
|
|
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
@@ -271,50 +372,89 @@ class DeployReplicaTargetResourcesTask(base.TaskRunner):
|
|
|
# can [try] to deal with the temporary resources.
|
|
# can [try] to deal with the temporary resources.
|
|
|
raise_on_error=False)
|
|
raise_on_error=False)
|
|
|
|
|
|
|
|
- volumes_info = _check_ensure_volumes_info_ordering(
|
|
|
|
|
- export_info, replica_resources_info["volumes_info"])
|
|
|
|
|
|
|
+ if "volumes_info" in replica_resources_info:
|
|
|
|
|
+ volumes_info = replica_resources_info["volumes_info"]
|
|
|
|
|
+ volumes_info = _check_ensure_volumes_info_ordering(
|
|
|
|
|
+ export_info, volumes_info)
|
|
|
|
|
+ else:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Replica target provider for '%s' did not return any "
|
|
|
|
|
+ "'volumes_info'. Using the previous value of it.")
|
|
|
|
|
+
|
|
|
|
|
+ migr_connection_info = {}
|
|
|
|
|
+ if 'connection_info' in replica_resources_info:
|
|
|
|
|
+ migr_connection_info = replica_resources_info['connection_info']
|
|
|
|
|
+ try:
|
|
|
|
|
+ backup_writers.BackupWritersFactory(
|
|
|
|
|
+ migr_connection_info, None).get_writer()
|
|
|
|
|
+ except Exception as err:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Seemingly invalid connection info. Replica will likely "
|
|
|
|
|
+ "fail during disk Replication. Error is: %s" % str(err))
|
|
|
|
|
+ else:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Replica target provider for '%s' did NOT return any "
|
|
|
|
|
+ "'connection_info'. Defaulting to %s",
|
|
|
|
|
+ destination["type"], migr_connection_info)
|
|
|
|
|
|
|
|
- task_info["volumes_info"] = volumes_info
|
|
|
|
|
- task_info["migr_target_resources"] = replica_resources_info[
|
|
|
|
|
- "migr_resources"]
|
|
|
|
|
|
|
+ target_resources = {}
|
|
|
|
|
+ if 'migr_resources' not in replica_resources_info:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Replica target provider for '%s' did NOT return any "
|
|
|
|
|
+ "'migr_resources'. Defaulting to %s",
|
|
|
|
|
+ destination["type"], target_resources)
|
|
|
|
|
+ else:
|
|
|
|
|
+ target_resources = replica_resources_info["migr_resources"]
|
|
|
|
|
|
|
|
- migr_connection_info = replica_resources_info["connection_info"]
|
|
|
|
|
- try:
|
|
|
|
|
- backup_writers.BackupWritersFactory(
|
|
|
|
|
- migr_connection_info, None).get_writer()
|
|
|
|
|
- except BaseException as err:
|
|
|
|
|
- LOG.exception(
|
|
|
|
|
- "Invalid connection info: %s" % err)
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "volumes_info": volumes_info,
|
|
|
|
|
+ "target_resources": target_resources,
|
|
|
|
|
+ "target_resources_connection_info": migr_connection_info}
|
|
|
|
|
|
|
|
- task_info["migr_target_connection_info"] = migr_connection_info
|
|
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+class DeleteReplicaTargetResourcesTask(base.TaskRunner):
|
|
|
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["target_resources", "target_environment"]
|
|
|
|
|
|
|
|
-class DeleteReplicaTargetResourcesTask(base.TaskRunner):
|
|
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return [
|
|
|
|
|
+ "target_resources", "target_resources_connection_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
event_handler):
|
|
event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
|
connection_info = base.get_connection_info(ctxt, destination)
|
|
connection_info = base.get_connection_info(ctxt, destination)
|
|
|
|
|
|
|
|
- migr_resources = task_info.get("migr_target_resources")
|
|
|
|
|
|
|
+ migr_resources = task_info.get("target_resources")
|
|
|
|
|
|
|
|
if migr_resources:
|
|
if migr_resources:
|
|
|
|
|
+ # TODO (aznashwan): add 'target_env' param to call:
|
|
|
provider.delete_replica_target_resources(
|
|
provider.delete_replica_target_resources(
|
|
|
ctxt, connection_info, migr_resources)
|
|
ctxt, connection_info, migr_resources)
|
|
|
|
|
|
|
|
- task_info["migr_target_resources"] = None
|
|
|
|
|
- task_info["migr_target_connection_info"] = None
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "target_resources": None,
|
|
|
|
|
+ "target_resources_connection_info": None}
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeployReplicaInstanceTask(base.TaskRunner):
|
|
class DeployReplicaInstanceTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
- target_environment = destination.get("target_environment") or {}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["export_info", "target_environment", "clone_disks"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["instance_deployment_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
|
|
+ target_environment = task_info["target_environment"]
|
|
|
export_info = task_info["export_info"]
|
|
export_info = task_info["export_info"]
|
|
|
|
|
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
@@ -330,23 +470,23 @@ class DeployReplicaInstanceTask(base.TaskRunner):
|
|
|
ctxt, connection_info, target_environment, instance,
|
|
ctxt, connection_info, target_environment, instance,
|
|
|
export_info, volumes_info, clone_disks)
|
|
export_info, volumes_info, clone_disks)
|
|
|
|
|
|
|
|
- if task_info.get("instance_deployment_info") is None:
|
|
|
|
|
- task_info["instance_deployment_info"] = {}
|
|
|
|
|
- task_info["instance_deployment_info"].update(import_info[
|
|
|
|
|
- "instance_deployment_info"])
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "instance_deployment_info": import_info[
|
|
|
|
|
+ 'instance_deployment_info']}
|
|
|
|
|
|
|
|
- task_info[
|
|
|
|
|
- "origin_provider_type"] = constants.PROVIDER_TYPE_REPLICA_EXPORT
|
|
|
|
|
- task_info[
|
|
|
|
|
- "destination_provider_type"
|
|
|
|
|
- ] = constants.PROVIDER_TYPE_REPLICA_IMPORT
|
|
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+class FinalizeReplicaInstanceDeploymentTask(base.TaskRunner):
|
|
|
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["instance_deployment_info"]
|
|
|
|
|
|
|
|
-class FinalizeReplicaInstanceDeploymentTask(base.TaskRunner):
|
|
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["transfer_result"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
@@ -355,19 +495,27 @@ class FinalizeReplicaInstanceDeploymentTask(base.TaskRunner):
|
|
|
|
|
|
|
|
result = provider.finalize_replica_instance_deployment(
|
|
result = provider.finalize_replica_instance_deployment(
|
|
|
ctxt, connection_info, instance_deployment_info)
|
|
ctxt, connection_info, instance_deployment_info)
|
|
|
- if result is not None:
|
|
|
|
|
- task_info["transfer_result"] = result
|
|
|
|
|
- else:
|
|
|
|
|
|
|
+ if result is None:
|
|
|
LOG.warn(
|
|
LOG.warn(
|
|
|
"'None' was returned as result for Finalize Replica Instance "
|
|
"'None' was returned as result for Finalize Replica Instance "
|
|
|
"deployment task '%s'.", task_info)
|
|
"deployment task '%s'.", task_info)
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "transfer_result": result}
|
|
|
|
|
|
|
|
|
|
|
|
|
class CleanupFailedReplicaInstanceDeploymentTask(base.TaskRunner):
|
|
class CleanupFailedReplicaInstanceDeploymentTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["instance_deployment_info"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["instance_deployment_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
@@ -378,12 +526,22 @@ class CleanupFailedReplicaInstanceDeploymentTask(base.TaskRunner):
|
|
|
provider.cleanup_failed_replica_instance_deployment(
|
|
provider.cleanup_failed_replica_instance_deployment(
|
|
|
ctxt, connection_info, instance_deployment_info)
|
|
ctxt, connection_info, instance_deployment_info)
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "instance_deployment_info": None}
|
|
|
|
|
|
|
|
|
|
|
|
|
class CreateReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
class CreateReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["export_info", "volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
@@ -400,14 +558,22 @@ class CreateReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
|
export_info, volumes_info)
|
|
export_info, volumes_info)
|
|
|
|
|
|
|
|
- task_info["volumes_info"] = volumes_info
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "volumes_info": volumes_info}
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeleteReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
class DeleteReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["export_info", "volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
export_info = task_info['export_info']
|
|
export_info = task_info['export_info']
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
@@ -424,14 +590,22 @@ class DeleteReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
|
export_info, volumes_info)
|
|
export_info, volumes_info)
|
|
|
|
|
|
|
|
- task_info["volumes_info"] = volumes_info
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "volumes_info": volumes_info}
|
|
|
|
|
|
|
|
|
|
|
|
|
class RestoreReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
class RestoreReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["export_info", "volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
provider = providers_factory.get_provider(
|
|
provider = providers_factory.get_provider(
|
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
|
|
|
event_handler)
|
|
event_handler)
|
|
@@ -448,14 +622,22 @@ class RestoreReplicaDiskSnapshotsTask(base.TaskRunner):
|
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
|
export_info, volumes_info)
|
|
export_info, volumes_info)
|
|
|
|
|
|
|
|
- task_info["volumes_info"] = volumes_info
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "volumes_info": volumes_info}
|
|
|
|
|
|
|
|
|
|
|
|
|
class ValidateReplicaExecutionSourceInputsTask(base.TaskRunner):
|
|
class ValidateReplicaExecutionSourceInputsTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["source_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return []
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
event_manager = events.EventManager(event_handler)
|
|
event_manager = events.EventManager(event_handler)
|
|
|
origin_type = origin["type"]
|
|
origin_type = origin["type"]
|
|
|
source_provider = providers_factory.get_provider(
|
|
source_provider = providers_factory.get_provider(
|
|
@@ -469,12 +651,21 @@ class ValidateReplicaExecutionSourceInputsTask(base.TaskRunner):
|
|
|
else:
|
|
else:
|
|
|
source_provider.validate_replica_export_input(
|
|
source_provider.validate_replica_export_input(
|
|
|
ctxt, origin_connection_info, instance,
|
|
ctxt, origin_connection_info, instance,
|
|
|
- source_environment=origin.get("source_environment", {}))
|
|
|
|
|
|
|
+ source_environment=task_info["source_environment"])
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {}
|
|
|
|
|
|
|
|
|
|
|
|
|
class ValidateReplicaExecutionDestinationInputsTask(base.TaskRunner):
|
|
class ValidateReplicaExecutionDestinationInputsTask(base.TaskRunner):
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["export_info", "target_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return []
|
|
|
|
|
+
|
|
|
def _validate_provider_replica_import_input(
|
|
def _validate_provider_replica_import_input(
|
|
|
self, provider, ctxt, conn_info, target_environment, export_info):
|
|
self, provider, ctxt, conn_info, target_environment, export_info):
|
|
|
provider.validate_replica_import_input(
|
|
provider.validate_replica_import_input(
|
|
@@ -482,8 +673,8 @@ class ValidateReplicaExecutionDestinationInputsTask(base.TaskRunner):
|
|
|
check_os_morphing_resources=False,
|
|
check_os_morphing_resources=False,
|
|
|
check_final_vm_params=False)
|
|
check_final_vm_params=False)
|
|
|
|
|
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
event_manager = events.EventManager(event_handler)
|
|
event_manager = events.EventManager(event_handler)
|
|
|
destination_type = destination["type"]
|
|
destination_type = destination["type"]
|
|
|
|
|
|
|
@@ -497,28 +688,35 @@ class ValidateReplicaExecutionDestinationInputsTask(base.TaskRunner):
|
|
|
event_manager.progress_update(
|
|
event_manager.progress_update(
|
|
|
"Replica Import Provider for platform '%s' does not support "
|
|
"Replica Import Provider for platform '%s' does not support "
|
|
|
"Replica input validation" % destination_type)
|
|
"Replica input validation" % destination_type)
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {}
|
|
|
|
|
|
|
|
export_info = task_info.get("export_info")
|
|
export_info = task_info.get("export_info")
|
|
|
if not export_info:
|
|
if not export_info:
|
|
|
- raise exception.CoriolisException(
|
|
|
|
|
|
|
+ raise exception.InvalidActionTasksExecutionState(
|
|
|
"Instance export info is not set. Cannot perform "
|
|
"Instance export info is not set. Cannot perform "
|
|
|
"Replica Import validation for destination platform "
|
|
"Replica Import validation for destination platform "
|
|
|
"'%s'" % destination_type)
|
|
"'%s'" % destination_type)
|
|
|
|
|
|
|
|
- # NOTE: the target environment JSON schema should have been validated
|
|
|
|
|
- # upon accepting the Replica API creation request.
|
|
|
|
|
- target_environment = destination.get("target_environment", {})
|
|
|
|
|
|
|
+ target_environment = task_info["target_environment"]
|
|
|
self._validate_provider_replica_import_input(
|
|
self._validate_provider_replica_import_input(
|
|
|
destination_provider, ctxt, destination_connection_info,
|
|
destination_provider, ctxt, destination_connection_info,
|
|
|
target_environment, export_info)
|
|
target_environment, export_info)
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {}
|
|
|
|
|
|
|
|
|
|
|
|
|
class ValidateReplicaDeploymentParametersTask(base.TaskRunner):
|
|
class ValidateReplicaDeploymentParametersTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["export_info", "target_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return []
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
event_manager = events.EventManager(event_handler)
|
|
event_manager = events.EventManager(event_handler)
|
|
|
destination_connection_info = base.get_connection_info(
|
|
destination_connection_info = base.get_connection_info(
|
|
|
ctxt, destination)
|
|
ctxt, destination)
|
|
@@ -538,43 +736,55 @@ class ValidateReplicaDeploymentParametersTask(base.TaskRunner):
|
|
|
"Replica Deployment Provider for platform '%s' does not "
|
|
"Replica Deployment Provider for platform '%s' does not "
|
|
|
"support Replica Deployment input validation" % (
|
|
"support Replica Deployment input validation" % (
|
|
|
destination_type))
|
|
destination_type))
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {}
|
|
|
|
|
|
|
|
# NOTE: the target environment JSON schema should have been validated
|
|
# NOTE: the target environment JSON schema should have been validated
|
|
|
# upon accepting the Replica API creation request.
|
|
# upon accepting the Replica API creation request.
|
|
|
- target_environment = destination.get("target_environment", {})
|
|
|
|
|
|
|
+ target_environment = task_info['target_environment']
|
|
|
destination_provider.validate_replica_deployment_input(
|
|
destination_provider.validate_replica_deployment_input(
|
|
|
ctxt, destination_connection_info, target_environment, export_info)
|
|
ctxt, destination_connection_info, target_environment, export_info)
|
|
|
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {}
|
|
|
|
|
|
|
|
|
|
|
|
|
class UpdateSourceReplicaTask(base.TaskRunner):
|
|
class UpdateSourceReplicaTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
- event_handler):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info", "source_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info", "source_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
+ event_handler):
|
|
|
event_manager = events.EventManager(event_handler)
|
|
event_manager = events.EventManager(event_handler)
|
|
|
|
|
+
|
|
|
|
|
+ volumes_info = task_info.get("volumes_info", [])
|
|
|
new_source_env = task_info.get('source_environment', {})
|
|
new_source_env = task_info.get('source_environment', {})
|
|
|
|
|
+ # NOTE: the `source_environment` in the `origin` is the one set
|
|
|
|
|
+ # in the dedicated DB column of the Replica and thus stores
|
|
|
|
|
+ # the previous value of it:
|
|
|
|
|
+ old_source_env = origin.get('source_environment')
|
|
|
if not new_source_env:
|
|
if not new_source_env:
|
|
|
event_manager.progress_update(
|
|
event_manager.progress_update(
|
|
|
"No new source environment options provided")
|
|
"No new source environment options provided")
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ 'volumes_info': volumes_info,
|
|
|
|
|
+ 'source_environment': old_source_env}
|
|
|
|
|
|
|
|
source_provider = providers_factory.get_provider(
|
|
source_provider = providers_factory.get_provider(
|
|
|
origin["type"], constants.PROVIDER_TYPE_SOURCE_REPLICA_UPDATE,
|
|
origin["type"], constants.PROVIDER_TYPE_SOURCE_REPLICA_UPDATE,
|
|
|
event_handler, raise_if_not_found=False)
|
|
event_handler, raise_if_not_found=False)
|
|
|
if not source_provider:
|
|
if not source_provider:
|
|
|
- raise exception.CoriolisException(
|
|
|
|
|
|
|
+ raise exception.InvalidActionTasksExecutionState(
|
|
|
"Replica source provider plugin for '%s' does not support"
|
|
"Replica source provider plugin for '%s' does not support"
|
|
|
" updating Replicas" % origin["type"])
|
|
" updating Replicas" % origin["type"])
|
|
|
|
|
|
|
|
origin_connection_info = base.get_connection_info(ctxt, origin)
|
|
origin_connection_info = base.get_connection_info(ctxt, origin)
|
|
|
- volumes_info = task_info.get("volumes_info", [])
|
|
|
|
|
|
|
|
|
|
LOG.info("Checking source provider environment params")
|
|
LOG.info("Checking source provider environment params")
|
|
|
- # NOTE: the `source_environment` in the `origin` is the one set
|
|
|
|
|
- # in the dedicated DB column of the Replica and thus stores
|
|
|
|
|
- # the previous value of it:
|
|
|
|
|
- old_source_env = origin.get('source_environment', {})
|
|
|
|
|
volumes_info = (
|
|
volumes_info = (
|
|
|
source_provider.check_update_source_environment_params(
|
|
source_provider.check_update_source_environment_params(
|
|
|
ctxt, origin_connection_info, instance, volumes_info,
|
|
ctxt, origin_connection_info, instance, volumes_info,
|
|
@@ -582,41 +792,59 @@ class UpdateSourceReplicaTask(base.TaskRunner):
|
|
|
if volumes_info:
|
|
if volumes_info:
|
|
|
schemas.validate_value(
|
|
schemas.validate_value(
|
|
|
volumes_info, schemas.CORIOLIS_VOLUMES_INFO_SCHEMA)
|
|
volumes_info, schemas.CORIOLIS_VOLUMES_INFO_SCHEMA)
|
|
|
|
|
+ else:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Source update method for '%s' source provider did NOT "
|
|
|
|
|
+ "return any volumes info. Defaulting to old value.",
|
|
|
|
|
+ origin["type"])
|
|
|
|
|
+ volumes_info = task_info.get("volumes_info", [])
|
|
|
|
|
|
|
|
- task_info['volumes_info'] = volumes_info
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "volumes_info": volumes_info,
|
|
|
|
|
+ "source_environment": new_source_env}
|
|
|
|
|
|
|
|
|
|
|
|
|
class UpdateDestinationReplicaTask(base.TaskRunner):
|
|
class UpdateDestinationReplicaTask(base.TaskRunner):
|
|
|
- def run(self, ctxt, instance, origin, destination, task_info,
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def required_task_info_properties(self):
|
|
|
|
|
+ return ["export_info", "volumes_info", "target_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def returned_task_info_properties(self):
|
|
|
|
|
+ return ["volumes_info", "target_environment"]
|
|
|
|
|
+
|
|
|
|
|
+ def _run(self, ctxt, instance, origin, destination, task_info,
|
|
|
event_handler):
|
|
event_handler):
|
|
|
event_manager = events.EventManager(event_handler)
|
|
event_manager = events.EventManager(event_handler)
|
|
|
- new_destination_env = task_info.get('destination_environment', {})
|
|
|
|
|
|
|
+
|
|
|
|
|
+ volumes_info = task_info.get("volumes_info", [])
|
|
|
|
|
+ new_destination_env = task_info.get('target_environment', {})
|
|
|
|
|
+ # NOTE: the `target_environment` in the `destination` is the one
|
|
|
|
|
+ # set in the dedicated DB column of the Replica and thus stores
|
|
|
|
|
+ # the previous value of it:
|
|
|
|
|
+ old_destination_env = destination.get('target_environment', {})
|
|
|
if not new_destination_env:
|
|
if not new_destination_env:
|
|
|
event_manager.progress_update(
|
|
event_manager.progress_update(
|
|
|
"No new destination environment options provided")
|
|
"No new destination environment options provided")
|
|
|
- return task_info
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ "target_environment": old_destination_env,
|
|
|
|
|
+ "volumes_info": volumes_info}
|
|
|
|
|
|
|
|
destination_provider = providers_factory.get_provider(
|
|
destination_provider = providers_factory.get_provider(
|
|
|
destination["type"],
|
|
destination["type"],
|
|
|
constants.PROVIDER_TYPE_DESTINATION_REPLICA_UPDATE,
|
|
constants.PROVIDER_TYPE_DESTINATION_REPLICA_UPDATE,
|
|
|
event_handler, raise_if_not_found=False)
|
|
event_handler, raise_if_not_found=False)
|
|
|
if not destination_provider:
|
|
if not destination_provider:
|
|
|
- raise exception.CoriolisException(
|
|
|
|
|
|
|
+ raise exception.InvalidActionTasksExecutionState(
|
|
|
"Replica destination provider plugin for '%s' does not "
|
|
"Replica destination provider plugin for '%s' does not "
|
|
|
"support updating Replicas" % destination["type"])
|
|
"support updating Replicas" % destination["type"])
|
|
|
|
|
|
|
|
destination_connection_info = base.get_connection_info(
|
|
destination_connection_info = base.get_connection_info(
|
|
|
ctxt, destination)
|
|
ctxt, destination)
|
|
|
export_info = task_info.get("export_info", {})
|
|
export_info = task_info.get("export_info", {})
|
|
|
- volumes_info = task_info.get("volumes_info", [])
|
|
|
|
|
|
|
|
|
|
LOG.info("Checking destination provider environment params")
|
|
LOG.info("Checking destination provider environment params")
|
|
|
- # NOTE: the `target_environment` in the `destination` is the one
|
|
|
|
|
- # set in the dedicated DB column of the Replica and thus stores
|
|
|
|
|
- # the previous value of it:
|
|
|
|
|
- old_destination_env = destination.get('target_environment', {})
|
|
|
|
|
volumes_info = (
|
|
volumes_info = (
|
|
|
destination_provider.check_update_destination_environment_params(
|
|
destination_provider.check_update_destination_environment_params(
|
|
|
ctxt, destination_connection_info, export_info, volumes_info,
|
|
ctxt, destination_connection_info, export_info, volumes_info,
|
|
@@ -627,7 +855,13 @@ class UpdateDestinationReplicaTask(base.TaskRunner):
|
|
|
volumes_info, schemas.CORIOLIS_VOLUMES_INFO_SCHEMA)
|
|
volumes_info, schemas.CORIOLIS_VOLUMES_INFO_SCHEMA)
|
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
volumes_info = _check_ensure_volumes_info_ordering(
|
|
|
export_info, volumes_info)
|
|
export_info, volumes_info)
|
|
|
-
|
|
|
|
|
- task_info['volumes_info'] = volumes_info
|
|
|
|
|
-
|
|
|
|
|
- return task_info
|
|
|
|
|
|
|
+ else:
|
|
|
|
|
+ LOG.warn(
|
|
|
|
|
+ "Destination update method for '%s' dest provider did NOT "
|
|
|
|
|
+ "return any volumes info. Defaulting to old value.",
|
|
|
|
|
+ destination["type"])
|
|
|
|
|
+ volumes_info = task_info.get("volumes_info", [])
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ "volumes_info": volumes_info,
|
|
|
|
|
+ "target_environment": new_destination_env}
|