Flows API
  • Globus Flows
  • Overview
  • Getting Started
    • How to Run a Flow
    • How to Monitor a Flow Run
    • How to Create a Flow
  • Authoring Flows
    • Introduction
    • Actions
    • Expressions
    • Choice States
    • Wait States
    • Fail States
    • Pass States
    • Protecting Secrets
    • Handling Exceptions
    • Performing Actions as Different Users
    • Run Context
    • Validating Flow Definitions
  • Authoring Input Schemas
  • Authentication and Authorization
  • Consents and Resuming Runs
  • Permissions
  • Limits
  • Hosted Action Providers
    • Hello World
    • Globus Search - Ingest Task
    • Globus Search - Delete Task
    • Send Notification Email
    • Wait For User Selection
    • Expression Evaluation
    • DataCite Mint
    • Transfer APs
    • Compute AP
  • Example Flows
    • Simple Transfer
    • Move (copy and delete) files
    • Transfer and Share Files
    • Two Stage Globus Transfer
    • Transfer After Approval
    • Looping Batched Move
    • Tar and Transfer with Globus Compute
Skip to main content
Globus Docs
  • APIs
    Auth Flows Groups Search Timers Transfer Globus Connect Server Compute Helper Pages
  • Applications
    Globus Connect Personal Globus Connect Server Premium Storage Connectors Compute Command Line Interface Python SDK JavaScript SDK
  • Guides
  • Support
    FAQs Mailing Lists Contact Us Check Support Tickets
  1. Home
  2. Globus Services
  3. Globus Flows
  4. Example Flows
  5. Two Stage Globus Transfer

Two Stage Globus Transfer

Description

Transfer from source to intermediate and then from intermediate to destination. Remove from intermediate after completion.

Note

This example differs from the Two Stage Globus Transfer Globus-provided flow available in the Globus Web App.

The example below is simplified and may exhibit slightly different behaviors.

Highlights

The ComputeTaskData state uses the run ID to create a unique temporary directory on the intermediate collection.

This helps ensure that existing data on the intermediate collection are not overwritten by accident.

Source code

{
  "Comment": "Transfer from a source collection to a destination collection using an intermediary collection",
  "StartAt": "GetSourcePathInfo",
  "States": {
    "GetSourcePathInfo": {
      "Comment": "Get the source path info",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/stat",
      "Parameters": {
        "endpoint_id.$": "$.source.id",
        "path.$": "$.source.path"
      },
      "ResultPath": "$.SourceStat",
      "Next": "GetIntermediatePathInfo"
    },
    "GetIntermediatePathInfo": {
      "Comment": "Get the intermediate path info",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/stat",
      "Parameters": {
        "endpoint_id.$": "$.intermediate.id",
        "path.$": "$.intermediate.path"
      },
      "ResultPath": "$.IntermediateStat",
      "Next": "GetDestinationPathInfo"
    },
    "GetDestinationPathInfo": {
      "Comment": "Get the destination path info",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/stat",
      "Parameters": {
        "endpoint_id.$": "$.destination.id",
        "path.$": "$.destination.path"
      },
      "ResultPath": "$.DestinationStat",
      "Next": "IdentifyPathTypes"
    },
    "IdentifyPathTypes": {
      "Comment": "Check the paths to see if they are directories or files",
      "Type": "ExpressionEval",
      "Parameters": {
        "source_is_dir.=": "SourceStat.details.type == 'dir'",
        "intermediate_is_dir.=": "'type' in IntermediateStat.details and IntermediateStat.details.type == 'dir'",
        "dest_is_dir.=": "'type' in DestinationStat.details and DestinationStat.details.type == 'dir'",
        "dest_exists.=": "'code' not in DestinationStat.details or DestinationStat.details.code != 'NotFound'",
        "source_is_default_dir.=": "source.path == '/~/'",
        "source_is_root.=": "source.path == '/'"
      },
      "ResultPath": "$.PathTypes",
      "Next": "TestPathConstraints"
    },
    "TestPathConstraints": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.PathTypes.intermediate_is_dir",
          "BooleanEquals": false,
          "Next": "FailIntermediateMustBeDir"
        },
        {
          "Variable": "$.PathTypes.dest_exists",
          "BooleanEquals": false,
          "Next": "ComputeIntermediatePath"
        },
        {
          "And": [
            {
              "Variable": "$.PathTypes.source_is_dir",
              "BooleanEquals": true
            },
            {
              "Variable": "$.PathTypes.dest_is_dir",
              "BooleanEquals": false
            }
          ],
          "Next": "FailSourceDestMismatchType"
        },
        {
          "And": [
            {
              "Variable": "$.PathTypes.source_is_dir",
              "BooleanEquals": false
            },
            {
              "Variable": "$.PathTypes.dest_is_dir",
              "BooleanEquals": true
            }
          ],
          "Next": "FailSourceDestMismatchType"
        }
      ],
      "Default": "ComputeIntermediatePath"
    },
    "ComputeIntermediatePath": {
      "Comment": "Determine the intermediate path based on the source path characteristics.",
      "Type": "ExpressionEval",
      "Parameters": {
        "basename.=": "source.path.rpartition('/')[2] if not PathTypes.source_is_dir else 'DEFAULT' if PathTypes.source_is_default_dir else 'ROOT' if PathTypes.source_is_root else source.path.split('/')[-2]"
      },
      "ResultPath": "$.ComputedIntermediatePath",
      "Next": "ComputeTaskData"
    },
    "ComputeTaskData": {
      "Comment": "Compute paths and labels",
      "Type": "ExpressionEval",
      "Parameters": {
        "intermediate_dir.=": "intermediate.path.rstrip('/') + '/' + _context.run_id + '/'",
        "intermediate_path.=": "intermediate.path.rstrip('/') + '/' + _context.run_id + '/' + ComputedIntermediatePath.basename"
      },
      "ResultPath": "$.ComputedTaskData",
      "Next": "MakeIntermediateDir"
    },
    "MakeIntermediateDir": {
      "Comment": "Create a temp directory on the intermediate to hold the data",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/mkdir",
      "Parameters": {
        "endpoint_id.$": "$.intermediate.id",
        "path.$": "$.ComputedTaskData.intermediate_dir"
      },
      "ResultPath": "$.MkdirResult",
      "Next": "Transfer1"
    },
    "Transfer1": {
      "Comment": "Run the initial transfer operation from the source collection to the intermediate collection",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/transfer",
      "WaitTime": 172800,
      "Parameters": {
        "source_endpoint.$": "$.source.id",
        "destination_endpoint.$": "$.intermediate.id",
        "DATA": [
          {
            "source_path.$": "$.source.path",
            "destination_path.$": "$.ComputedTaskData.intermediate_path"
          }
        ]
      },
      "ResultPath": "$.Transfer1Result",
      "Next": "Transfer2"
    },
    "Transfer2": {
      "Comment": "Run the second transfer operation from the intermediate collection to the destination collection",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/transfer",
      "WaitTime": 172800,
      "Parameters": {
        "source_endpoint.$": "$.intermediate.id",
        "destination_endpoint.$": "$.destination.id",
        "DATA": [
          {
            "source_path.=": "ComputedTaskData.intermediate_path",
            "destination_path.$": "$.destination.path"
          }
        ]
      },
      "ResultPath": "$.Transfer2Result",
      "Next": "Delete"
    },
    "Delete": {
      "Comment": "Delete the data from the intermediate collection",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/delete",
      "WaitTime": 172800,
      "Parameters": {
        "endpoint.$": "$.intermediate.id",
        "recursive": true,
        "DATA": [
          {
            "path.$": "$.ComputedTaskData.intermediate_dir"
          }
        ]
      },
      "ResultPath": "$.DeleteResult",
      "Next": "Success"
    },
    "FailSourceDestMismatchType": {
      "Comment": "Report failure due to a transfer of a directory to a file or vice-versa",
      "Type": "Fail",
      "Cause": "SourceDestMismatchType",
      "Error": "If the source is a directory, the destination must be a directory. And if the source is a file, the destination must be a file."
    },
    "FailIntermediateMustBeDir": {
      "Comment": "Report failure due to a transfer to a file or nonexistent dest on the intermediate collection",
      "Type": "Fail",
      "Cause": "IntermediateIsFile",
      "Error": "The intermediate path must be a directory and must exist prior to use."
    },
    "Success": {
      "Comment": "Normal completion, so report success and exit",
      "Type": "Pass",
      "Parameters": {
        "message": "Two Stage Transfer complete"
      },
      "ResultPath": "$.FlowResult",
      "End": true
    }
  }
}
{
  "type": "object",
  "required": [
    "source",
    "intermediate",
    "destination"
  ],
  "properties": {
    "source": {
      "type": "object",
      "title": "Source",
      "format": "globus-collection",
      "required": [
        "id",
        "path"
      ],
      "properties": {
        "id": {
          "type": "string",
          "title": "Source Collection ID",
          "format": "uuid",
          "description": "The UUID for the collection which serves as the source of the data for the two-stage Transfer"
        },
        "path": {
          "type": "string",
          "title": "Source Collection Path",
          "description": "The path on the source collection for the data"
        }
      },
      "description": "The data's origin",
      "additionalProperties": false
    },
    "intermediate": {
      "type": "object",
      "title": "Intermediate",
      "format": "globus-collection",
      "required": [
        "id",
        "path"
      ],
      "properties": {
        "id": {
          "type": "string",
          "title": "Intermediate Collection ID",
          "format": "uuid",
          "description": "The UUID for the collection which serves as the intermediate, temporary storage for the Transfer"
        },
        "path": {
          "type": "string",
          "title": "Intermediate Collection Path",
          "description": "The path on the intermediate collection where the data will reside until the end-to-end Transfer is complete."
        }
      },
      "description": "An intermediate location used to hold data, often used to manage network usage",
      "additionalProperties": false
    },
    "destination": {
      "type": "object",
      "title": "Destination",
      "format": "globus-collection",
      "required": [
        "id",
        "path"
      ],
      "properties": {
        "id": {
          "type": "string",
          "title": "Destination Collection ID",
          "format": "uuid",
          "description": "The UUID for the collection which serves as the destination for the two-stage Transfer"
        },
        "path": {
          "type": "string",
          "title": "Destination Collection Path",
          "description": "The path on the destination collection where the data will be stored"
        }
      },
      "description": "The destination for the data.",
      "additionalProperties": false
    }
  },
  "additionalProperties": false
}
{
  "source": {
    "id": "6c54cade-bde5-45c1-bdea-f4bd71dba2cc",
    "path": "/~/ep1-example-directory/"
  },
  "intermediate": {
    "id": "31ce9ba0-176d-45a5-add3-f37d233ba47d",
    "path": "/~/ep2-intermediate-directory/"
  },
  "destination": {
    "id": "6c54cade-bde5-45c1-bdea-f4bd71dba2cc",
    "path": "/~/ep1-duplicate-example-directory/"
  }
}
  • Globus Flows
  • Overview
  • Getting Started
    • How to Run a Flow
    • How to Monitor a Flow Run
    • How to Create a Flow
  • Authoring Flows
    • Introduction
    • Actions
    • Expressions
    • Choice States
    • Wait States
    • Fail States
    • Pass States
    • Protecting Secrets
    • Handling Exceptions
    • Performing Actions as Different Users
    • Run Context
    • Validating Flow Definitions
  • Authoring Input Schemas
  • Authentication and Authorization
  • Consents and Resuming Runs
  • Permissions
  • Limits
  • Hosted Action Providers
    • Hello World
    • Globus Search - Ingest Task
    • Globus Search - Delete Task
    • Send Notification Email
    • Wait For User Selection
    • Expression Evaluation
    • DataCite Mint
    • Transfer APs
    • Compute AP
  • Example Flows
    • Simple Transfer
    • Move (copy and delete) files
    • Transfer and Share Files
    • Two Stage Globus Transfer
    • Transfer After Approval
    • Looping Batched Move
    • Tar and Transfer with Globus Compute
© 2010- The University of Chicago Legal Privacy Accessibility