diff --git a/ivy.xml b/ivy.xml
index 3df9e6a28..8b3222da1 100644
--- a/ivy.xml
+++ b/ivy.xml
@@ -45,6 +45,9 @@
+
+
+
diff --git a/java/src/org/broadinstitute/sting/gatk/CommandLineExecutable.java b/java/src/org/broadinstitute/sting/gatk/CommandLineExecutable.java
index bbe037154..c11d246df 100644
--- a/java/src/org/broadinstitute/sting/gatk/CommandLineExecutable.java
+++ b/java/src/org/broadinstitute/sting/gatk/CommandLineExecutable.java
@@ -129,10 +129,7 @@ public abstract class CommandLineExecutable extends CommandLineProgram {
private void generateGATKRunReport(Walker,?> walker, Exception e) {
if ( getArgumentCollection().phoneHomeType != GATKRunReport.PhoneHomeOption.NO_ET ) {
GATKRunReport report = new GATKRunReport(walker, e, engine, getArgumentCollection().phoneHomeType );
- if ( getArgumentCollection().phoneHomeType == GATKRunReport.PhoneHomeOption.STDOUT )
- report.postReport(System.out);
- else
- report.postReport();
+ report.postReport(getArgumentCollection().phoneHomeType);
}
}
diff --git a/java/src/org/broadinstitute/sting/gatk/arguments/GATKArgumentCollection.java b/java/src/org/broadinstitute/sting/gatk/arguments/GATKArgumentCollection.java
index 891fe5120..152765cc1 100755
--- a/java/src/org/broadinstitute/sting/gatk/arguments/GATKArgumentCollection.java
+++ b/java/src/org/broadinstitute/sting/gatk/arguments/GATKArgumentCollection.java
@@ -86,6 +86,11 @@ public class GATKArgumentCollection {
@Argument(fullName = "phone_home", shortName = "et", doc="What kind of GATK run report should we generate? Standard is the default, can be verbose or NO_ET so nothing is posted to the run repository", required = false)
public GATKRunReport.PhoneHomeOption phoneHomeType = GATKRunReport.PhoneHomeOption.STANDARD;
+ @Element(required = false)
+ @Argument(fullName = "S3SecretKey", shortName = "s3sk", doc="Secret key to be used for AWS S3 interactions", required = false)
+ public String S3SecretKey = null;
+
+
@ElementList(required = false)
@Argument(fullName = "read_filter", shortName = "rf", doc = "Specify filtration criteria to apply to each read individually.", required = false)
public List readFilters = new ArrayList();
@@ -391,9 +396,15 @@ public class GATKArgumentCollection {
(other.RODToInterval != null && !other.RODToInterval.equals(RODToInterval))) {
return false;
}
+
if (other.phoneHomeType != this.phoneHomeType) {
return false;
}
+ if ((other.S3SecretKey == null && this.S3SecretKey != null) ||
+ (other.S3SecretKey != null && !other.S3SecretKey.equals(this.S3SecretKey))) {
+ return false;
+ }
+
if (BTIMergeRule != other.BTIMergeRule)
return false;
diff --git a/java/src/org/broadinstitute/sting/gatk/phonehome/GATKRunReport.java b/java/src/org/broadinstitute/sting/gatk/phonehome/GATKRunReport.java
index 388aac1ce..6abeb5643 100644
--- a/java/src/org/broadinstitute/sting/gatk/phonehome/GATKRunReport.java
+++ b/java/src/org/broadinstitute/sting/gatk/phonehome/GATKRunReport.java
@@ -32,7 +32,14 @@ import org.broadinstitute.sting.gatk.arguments.GATKArgumentCollection;
import org.broadinstitute.sting.gatk.walkers.Walker;
import org.broadinstitute.sting.utils.exceptions.ReviewedStingException;
import org.broadinstitute.sting.utils.Utils;
+import org.broadinstitute.sting.utils.exceptions.StingException;
import org.broadinstitute.sting.utils.exceptions.UserException;
+import org.jets3t.service.S3Service;
+import org.jets3t.service.S3ServiceException;
+import org.jets3t.service.impl.rest.httpclient.RestS3Service;
+import org.jets3t.service.model.S3Bucket;
+import org.jets3t.service.model.S3Object;
+import org.jets3t.service.security.AWSCredentials;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Serializer;
@@ -42,6 +49,7 @@ import org.simpleframework.xml.stream.HyphenStyle;
import java.io.*;
import java.net.InetAddress;
+import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -67,6 +75,8 @@ public class GATKRunReport {
*/
private static File REPORT_DIR = new File("/humgen/gsa-hpprojects/GATK/reports");
+ private static final String REPORT_BUCKET_NAME = "GATK_Run_Reports";
+
/**
* The full path to the direct where submitted (and uncharacterized) report files are written
*/
@@ -145,18 +155,18 @@ public class GATKRunReport {
@Element(required = true, name = "reads")
private long nReads;
-// @Element(required = true, name = "read_metrics")
-// private String readMetrics;
-
// TODO
// todo md5 all filenames
// todo size of filenames
+ private String S3SecretKey = null;
+
public enum PhoneHomeOption {
NO_ET,
STANDARD,
DEV,
- STDOUT
+ STDOUT,
+ AWS_S3
}
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH.mm.ss");
@@ -210,7 +220,7 @@ public class GATKRunReport {
// user and hostname -- information about the runner of the GATK
userName = System.getProperty("user.name");
- hostName = resolveHostname();
+ hostName = "unknown"; // resolveHostname();
// basic java information
java = Utils.join("-", Arrays.asList(System.getProperty("java.vendor"), System.getProperty("java.version")));
@@ -218,6 +228,8 @@ public class GATKRunReport {
// if there was an exception, capture it
this.mException = e == null ? null : new ExceptionToXML(e);
+
+ this.S3SecretKey = engine.getArguments().S3SecretKey;
}
public String getID() {
@@ -232,14 +244,36 @@ public class GATKRunReport {
* @return
*/
private String resolveHostname() {
- return "unknown";
-// try {
-// return InetAddress.getLocalHost().getCanonicalHostName();
-// }
-// catch (java.net.UnknownHostException uhe) { // [beware typo in code sample -dmw]
-// return "unresolvable";
-// // handle exception
-// }
+ try {
+ return InetAddress.getLocalHost().getCanonicalHostName();
+ }
+ catch (java.net.UnknownHostException uhe) { // [beware typo in code sample -dmw]
+ return "unresolvable";
+ // handle exception
+ }
+ }
+
+ public void postReport(PhoneHomeOption type) {
+ switch (type) {
+ case NO_ET: // don't do anything
+ break;
+ case STANDARD: case DEV:
+ if ( repositoryIsOnline() ) {
+ postReportToLocalDisk(REPORT_SUBMIT_DIR);
+ } else {
+ logger.debug("Not writing report: sentinel " + REPORT_SENTINEL + " doesn't exist");
+ }
+ break;
+ case STDOUT:
+ postReportToStream(System.out);
+ break;
+ case AWS_S3:
+ postReportToAWSS3();
+ break;
+ default:
+ exceptDuringRunReport("BUG: unexcepted PhoneHomeOption ");
+ break;
+ }
}
/**
@@ -248,7 +282,7 @@ public class GATKRunReport {
*
* @param stream
*/
- public void postReport(OutputStream stream) {
+ private void postReportToStream(OutputStream stream) {
Serializer serializer = new Persister(new Format(new HyphenStyle()));
try {
serializer.write(this, stream);
@@ -264,13 +298,13 @@ public class GATKRunReport {
* @param destination
* @throws IOException
*/
- public void postReport(File destination) throws IOException {
+ private void postReportToFile(File destination) throws IOException {
BufferedOutputStream out =
new BufferedOutputStream(
new GZIPOutputStream(
new FileOutputStream(destination)));
try {
- postReport(out);
+ postReportToStream(out);
} finally {
out.close();
}
@@ -281,22 +315,74 @@ public class GATKRunReport {
* If this process fails for any reason, all exceptions are handled and this routine merely prints a warning.
* That is, postReport() is guarenteed not to fail for any reason.
*/
- public void postReport() {
+ private File postReportToLocalDisk(File rootDir) {
try {
- if ( repositoryIsOnline() ) {
- String filename = getID() + ".report.xml.gz";
- File file = new File(REPORT_SUBMIT_DIR, filename);
- postReport(file);
- logger.info("Wrote report to " + file);
- } else {
- logger.debug("Not writing report: sentinel " + REPORT_SENTINEL + " doesn't exist");
- }
+ String filename = getID() + ".report.xml.gz";
+ File file = new File(rootDir, filename);
+ postReportToFile(file);
+ logger.info("Wrote report to " + file);
+ return file;
} catch ( Exception e ) {
// we catch everything, and no matter what eat the error
- logger.warn("Received error while posting report. GATK continuing on but no run report has been generated because: " + e.getMessage());
+ exceptDuringRunReport("Couldn't read report file", e);
+ return null;
}
}
+ private void postReportToAWSS3() {
+ // modifying example code from http://jets3t.s3.amazonaws.com/toolkit/code-samples.html
+ if ( S3SecretKey == null )
+ exceptDuringRunReport("Cannot upload run reports to AWS S3 without providing a secret key on the command line");
+ else {
+ this.hostName = resolveHostname(); // we want to fill in the host name
+ File localFile = postReportToLocalDisk(new File("./"));
+ logger.info("Generating GATK report to AWS S3 based on local file " + localFile);
+ if ( localFile != null ) {
+ try {
+ // we succeeded in creating the local file
+
+ // Your Amazon Web Services (AWS) login credentials are required to manage S3 accounts. These credentials
+ // are stored in an AWSCredentials object:
+ String awsAccessKey = "AKIAJQQEIHTAHSM333EQ";
+ AWSCredentials awsCredentials = new AWSCredentials(awsAccessKey, S3SecretKey);
+
+ // To communicate with S3, create a class that implements an S3Service. We will use the REST/HTTP
+ // implementation based on HttpClient, as this is the most robust implementation provided with JetS3t.
+ S3Service s3Service = new RestS3Service(awsCredentials);
+
+ // grab the reports bucket
+ S3Bucket reportsBucket = s3Service.getBucket(REPORT_BUCKET_NAME);
+ logger.info("Uploading to bucket: " + reportsBucket);
+
+ // Create an S3Object based on a file, with Content-Length set automatically and
+ // Content-Type set based on the file's extension (using the Mimetypes utility class)
+ S3Object fileObject = new S3Object(localFile);
+ logger.info("Created S3Object" + fileObject);
+ logger.info("Uploading " + localFile + " to AWS bucket");
+ s3Service.putObject(reportsBucket, fileObject);
+ //logger.info("Done. File hash value: " + fileObject.getMd5HashAsHex());
+ } catch ( S3ServiceException e ) {
+ exceptDuringRunReport("S3 exception occurred", e);
+ } catch ( NoSuchAlgorithmException e ) {
+ exceptDuringRunReport("Couldn't calculate MD5", e);
+ } catch ( IOException e ) {
+ exceptDuringRunReport("Couldn't read report file", e);
+ } finally {
+ localFile.delete();
+ }
+ }
+ }
+ }
+
+ private void exceptDuringRunReport(String msg, Throwable e) {
+ logger.warn("An occurred during GATK run reporting [everything is fine, but no report could be generated]. Message is: " + msg + ". Error message is: " + e.getMessage() + ". Stack track follows" + e.getStackTrace());
+ }
+
+ private void exceptDuringRunReport(String msg) {
+ logger.warn("An occurred during GATK run reporting [everything is fine, but no report could be generated]. Message is " + msg);
+ }
+
+
/**
* Returns true if and only if the common run report repository is available and online to receive reports
*