GT 4.0 Reliable File Transfer (RFT) Service: Developer's Guide

1. Introduction

RFT Service implementation in GT 4.0 uses standard SOAP messages over HTTP to submit and manage a set of 3rd party GridFTP transfers and to delete files using GridFTP. The user creates a RFT resource by submitting a list of URL pairs of  files that need to be transferred/deleted  to RFT Factory service. The user also specifies the time to live for the resource the user is creating to a GT 4.0 container in which RFT is deployed and configured. The resource is created after the user is properly authorized and authenticated. RFT service implementation exposes operations to control and manage the transfers (the resource). The operations exposed by both RFT factory and RFT service are briefly described below. The resource the user created also exposes the state of the transfer as a resource property to which the user can either subscribe for changes or poll for the changes in state periodically using standard command line clients.

2. Before you begin

2.1. Feature summary

Features new in GT 4.0

  • No new features since GT 3.9.5.

Supported Features

  • Delete files: Delete a set of files/directories on a GridFTP server.
  • Exponential Backoff: Configurable exponential back off before a failed transfer is retried.
  • Transfer All or None: If this option is set and one of the transfers in the request fails, RFT will stop transferring the remainder of the request and delete the files that were already transferred successfully.
  • Transfer Permissions: File permissions are restored at the destination once the file is transfered successfully. This can be configured to throw a fatal error or a transient error depending on whether the GridFTP server supports the MLST command.
  • Configurable number of concurrent transfers per container and per request.
  • Better error reporting and faults.
  • Database purge of the request and transfers after life time expiration.
  • Cumulative (aggregate ) Resource Properties on the factory provide some statistical information.
  • One status Resource Property for the entire transfer.
  • Recursive directory transfers and deletes.
  • Parallel streams.
  • TCP Buffer Size.
  • Third-party directory transfers, file transfers and deletes.
  • Data channel authentication (DCAU).
  • NoTPT option.
  • Different subject names for source and destination GridFTP servers for the authorization mechanism.
  • Support for binary/ascii type of transfers.
  • Configurable number of retries for failed transfers per request.
  • Block Size in bytes.

Deprecated Features

  • None

2.2. Tested platforms

Tested platforms for RFT:

  • Linux

    • Fedora Core 1 i686
    • Fedora Core 3 i686
    • RedHat 7.3 i686
    • RedHat 9 x86
    • Debian Sarge x86
    • Debian 3.1 i686
  • Mac OS X

    • Mac OS X 10.3, 10.4

Tested containers for RFT:

  • Java WS Core container
  • Tomcat 5.0.30

2.3. Backward compatibility summary

Protocol changes since GT 3.2

  • Added All or None option, maximum attempts, and finishBy to the transfer request
  • Not backwards compatible with the OGSI version

API changes since GT 3.2

  • None

Exception changes since GT 3.2

  • None

Schema changes since GT 3.2

  • WSDL changes to work with the new Java WS Core

2.4. Technology dependencies

RFT depends on the following GT components:

  • Java WS Core
  • WS Authentication and Authorization
  • Delegation Service
  • Service Groups
  • MDS useful RP

RFT depends on the following 3rd party software:

  • PostgreSQL 7.1 or later. Not tested with 8.0 yet.

2.5. Security considerations

2.5.1. Permissions of service configuration files

The service configuration files such as jndi-config.xml and server-config.wsdd (located under etc/<gar>/ directory) contain private information such as database passwords and usernames. Ensure that these configuration files are only readable by the user that is running the container.

The deployment process automatically sets the permissions of jndi-config.xml and server-config.wsdd as user readable only. However, this might not work correctly on all platforms and this does not apply to any other configuration files.

2.5.2. Access of information stored in the database

RFT stores the transfer requests in a database. Proper security measures need to be taken to protect the access of the data by granting/revoking appropriate permissions on tables that are created for RFT use and other steps that are appropriate and consistent with site specific security measures.

2.5.3. Permissions of persistent data

RFT uses the subscription persistence API from the GT4 core to store all of its subscription data under the ~/.globus/persisted directory. Ensure that the entire ~/.globus/persisted directory is only readable by the user running the container.

3. Architecture and design overview

A design doc can be found here.

4. Public Interface

The semantics and syntax of the APIs and WSDL for the component, along with descriptions of domain-specific structured interface data, can be found in the Public Interface Guide.

5. Usage scenarios

5.1. Transferring large datasets using GridFTP

RFT is primarily used to reliably transfer large datasets using GridFTP. If you are a developer and would like to use RFT, the following steps would help you to do that.

  • Contact the Delegation Factory Service and get an EPR for the Delegation Resource that contains your delegated credential.

    
     public static EndpointReferenceType
            delegateCredential(String host, String port) throws Exception {
            ClientSecurityDescriptor desc = new ClientSecurityDescriptor();
            // Credential to sign with, assuming default credential
            GlobusCredential credential = GlobusCredential.getDefaultCredential();
            desc.setGSITransport(Constants.GSI_TRANSPORT)
            Util.registerTransport();
            desc.setAuthz('host');
    
            String factoryUrl = PROTOCOL + "://" + host + ":"
                            + port + SERVICE_URL_ROOT
                            + DelegationConstants.FACTORY_PATH;
    
            // lifetime in seconds
            int lifetime = TERM_TIME * 60;
    
            // Get the public key to delegate on.
            EndpointReferenceType delegEpr = AddressingUtils
                    .createEndpointReference(factoryUrl, null);
            X509Certificate[] certsToDelegateOn = DelegationUtil
                    .getCertificateChainRP(delegEpr, desc);
            X509Certificate certToSign = certsToDelegateOn[0];
            return DelegationUtil.delegate(factoryUrl,
                        credential, certToSign, lifetime, false,
                        desc);
        }
        

  • Now construct a TransferRequestType Object:

    
        TransferType[] transferArray = new TransferType[1];
        transferArray[0] = new TransferType();
        transferArray[0].setSourceUrl("gsiftp://foo/bar");
        transferArray[0].setDestinationUrl("gsiftp://blah/");
        RFTOptionsType rftOptions = new RFTOptionsType();
        rftOptions.setBinary(true);
        // You can set more options like parallel streams, buffer sizes etc
        // Refer to Public Interface guide of RFT for more details
        TransferRequestType request = new TransferRequestType();
        request.setRftOptions(rftOptions);
        request.setTransfer(transferArray);
        request.setTransferCredentialEndpoint(delegateCredential(host,port));
        

  • Now contact the RFT factory and create an RFT resource:

    
          public static EndpointReferenceType createRFT(String rftFactoryAddress,
                BaseRequestType request) 
        throws Exception {
            endpoint = new URL(rftFactoryAddress);
            factoryPort = rftFactoryLocator
                    .getReliableFileTransferFactoryPortTypePort(endpoint);
            CreateReliableFileTransferInputType input =
                new CreateReliableFileTransferInputType();
            //input.setTransferJob(transferType);
            if(request instanceof TransferRequestType) {
                input.setTransferRequest((TransferRequestType)request);
            } else {
                input.setDeleteRequest((DeleteRequestType)request);
            }
            Calendar termTime = Calendar.getInstance();
            termTime.add(Calendar.HOUR, 1);
            input.setInitialTerminationTime(termTime);
            setSecurity((Stub)factoryPort);
            CreateReliableFileTransferOutputType response = factoryPort
                    .createReliableFileTransfer(input);
    
            return response.getReliableTransferEPR();
        }
    

  • Now contact the RFT service Implementation and call start to actually start the transfer:

    
    ReliableFileTransferPortType rft = rftLocator
                    .getReliableFileTransferPortTypePort(rftepr);
            setSecurity((Stub)rft);
    
            //For secure notifications
            subscribe(rft);
            System.out.println("Subscribed for overall status");
            //End subscription code
            Calendar termTime = Calendar.getInstance();
            termTime.add(Calendar.MINUTE, TERM_TIME);
            SetTerminationTime reqTermTime = new SetTerminationTime();
            reqTermTime.setRequestedTerminationTime(termTime);
            System.out.println("Termination time to set: " + TERM_TIME
                    + " minutes");
            SetTerminationTimeResponse termRes = rft
                    .setTerminationTime(reqTermTime);
            StartOutputType startresp = rft.start(new Start());
    

5.2. Deleting a set of files and directories using GridFTP

RFT can also be used to delete a set of files and directories using GridFTP server. The following steps depict how to:

  • Contact the Delegation Factory Service and get an EPR for the Delegation Resource that contains your delegated credential.

    
     public static EndpointReferenceType
            delegateCredential(String host, String port) throws Exception {
            ClientSecurityDescriptor desc = new ClientSecurityDescriptor();
            // Credential to sign with, assuming default credential
            GlobusCredential credential = GlobusCredential.getDefaultCredential();
            desc.setGSITransport(Constants.GSI_TRANSPORT)
            Util.registerTransport();
            desc.setAuthz('host');
    
            String factoryUrl = PROTOCOL + "://" + host + ":"
                            + port + SERVICE_URL_ROOT
                            + DelegationConstants.FACTORY_PATH;
    
            // lifetime in seconds
            int lifetime = TERM_TIME * 60;
    
            // Get the public key to delegate on.
            EndpointReferenceType delegEpr = AddressingUtils
                    .createEndpointReference(factoryUrl, null);
            X509Certificate[] certsToDelegateOn = DelegationUtil
                    .getCertificateChainRP(delegEpr, desc);
            X509Certificate certToSign = certsToDelegateOn[0];
            return DelegationUtil.delegate(factoryUrl,
                        credential, certToSign, lifetime, false,
                        desc);
        }
        

  • Now construct a DeleteRequestType object:

    
        DeleteType[] deleteArray = new DeleteType[1];
        deleteArray[0] = new DeleteType();
        deleteArray[0].setFile("gsiftp://foo/bar");
        DeleteOptionsType deleteOptions = new DeleteOptionsType();
        deleteOptions.setSubjectName("SUBJECT-NAME");
        DeleteRequestType request = new DeleteRequestType();
        request.setDeleteOptions(deleteOptions);
        request.setDeletion(deleteArray);
        request.setTransferCredentialEndpoint(delegateCredential(host,port));
        

  • Now contact the RFT factory and create an RFT resource:

    
          public static EndpointReferenceType createRFT(String rftFactoryAddress,
                BaseRequestType request) 
        throws Exception {
            endpoint = new URL(rftFactoryAddress);
            factoryPort = rftFactoryLocator
                    .getReliableFileTransferFactoryPortTypePort(endpoint);
            CreateReliableFileTransferInputType input =
                new CreateReliableFileTransferInputType();
            //input.setTransferJob(transferType);
            if(request instanceof TransferRequestType) {
                input.setTransferRequest((TransferRequestType)request);
            } else {
                input.setDeleteRequest((DeleteRequestType)request);
            }
            Calendar termTime = Calendar.getInstance();
            termTime.add(Calendar.HOUR, 1);
            input.setInitialTerminationTime(termTime);
            setSecurity((Stub)factoryPort);
            CreateReliableFileTransferOutputType response = factoryPort
                    .createReliableFileTransfer(input);
    
            return response.getReliableTransferEPR();
        }
    

  • Now contact the RFT service Implementation and call start to actually start the transfer:

    
    ReliableFileTransferPortType rft = rftLocator
                    .getReliableFileTransferPortTypePort(rftepr);
            setSecurity((Stub)rft);
    
            //For secure notifications
            subscribe(rft);
            System.out.println("Subscribed for overall status");
            //End subscription code
            Calendar termTime = Calendar.getInstance();
            termTime.add(Calendar.MINUTE, TERM_TIME);
            SetTerminationTime reqTermTime = new SetTerminationTime();
            reqTermTime.setRequestedTerminationTime(termTime);
            System.out.println("Termination time to set: " + TERM_TIME
                    + " minutes");
            SetTerminationTimeResponse termRes = rft
                    .setTerminationTime(reqTermTime);
            StartOutputType startresp = rft.start(new Start());
    

6. Tutorials

There are no tutorials available at this point.

7. Debugging

A standard way to debug RFT is to make the container print out more verbose error messages. You can do this with the following steps:

Edit $GLOBUS_LOCATION/container-log4j.properties and add following line to it: log4j.category.org.globus.transfer=DEBUG. For more verbosity add log4j.category.org.globus.ftp=DEBUG , which will print out Gridftp messages too.

8. Troubleshooting

8.1. Database configuration

Database configuration is the most complicated and important part of RFT setup. You can find more instructions on troubleshooting in Section 8, “Troubleshooting”.

8.2.  RFT fault-tolerance and recovery

RFT uses PostgreSQL to check-point transfer state in the form of restart markers and recover from transient transfer failures, using retry mechanism with exponential backoff, during a transfer. RFT has been tested to recover from source and/or destination server crashes during a transfer, network failures, container failures (when the machine running the container goes down), file system failures, etc. RFT Resource is implemented as a PersistentResource, so ReliableFileTransferHome gets initialized every time a container gets restarted. Please find a more detailed description of fault-tolerance and recovery in RFT below:

  • Source and/or destination GridFTP failures: In this case RFT retries the transfer for a configurable number of maximum attempts with exponential backoff for each retry (the backoff time period is configurable also). If a failure happens in the midst of a transfer, RFT uses the last restart marker that is stored in the database for that transfer and uses it to resume the transfer from the point where it failed, instead of restarting the whole file. This failure is treated as a container-wide backoff for the server in question. What this means is that all other transfers going to/from that server, across all the requests in a container, will be backed off and retried. This is done in order to prevent further failures of the transfers by using knowledge available in the database.
  • Network failures: Sometimes this happens due to heavy load on a network or for any other reason packets are lost or connections get timed out. This failure is considered a transient failure and RFT retries the transfer with exponential backoff for that particular transfer (and not the whole container, as with the source and/or destination GridFTP failures).
  • Container failures: These type of failures occur when the machine running the container goes down or if the container is restarted with active transfers. When the container is restarted, it restarts ReliableTransferHome, which looks at the database for any active RFT resources and restarts them.

8.2.1. Failure modes that are not addressed:

  • Running out of disk space for the database.