/* * Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package org.akvo.flow.deploy; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Date; import com.amazonaws.AmazonClientException; import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.CannedAccessControlList; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.PutObjectResult; import com.google.appengine.api.datastore.DatastoreService; import com.google.appengine.api.datastore.DatastoreServiceFactory; import com.google.appengine.api.datastore.Entity; import com.google.appengine.tools.remoteapi.RemoteApiInstaller; import com.google.appengine.tools.remoteapi.RemoteApiOptions; /** * Uploads a single Akvo FLOW APK to s3. There are seven arguments: - accessKey * - S3 access key - secretKey - S3 secret key - instanceId - name of the * instance, - apkPath - the local path to the APK file to be - version - APK * version name - username - Google Account username - password - Google Account * password */ public class Deploy { private static final int S3_ACCESS_KEY = 0; private static final int S3_SECRET_KEY = 1; private static final int INSTANCE_ID = 2; private static final int APK_PATH = 3; private static final int VERSION = 4; private static final int ACCOUNT_ID = 5; private static final int ACCOUNT_SECRET = 6; private static final String BUCKET_NAME = "akvoflow"; public static void main(String[] args) throws IOException { if (args.length != 7) { System.err.println("Missing argument, please provide S3 access key, S3 secret key, " + "instanceId , apkPath, version, GAE username and GAE password"); return; } File file = new File(args[APK_PATH]); if (!file.exists()) { System.err.println("Can't find apk at " + args[APK_PATH]); return; } final String accessKey = args[S3_ACCESS_KEY]; final String secretKey = args[S3_SECRET_KEY]; final String instance = args[INSTANCE_ID]; final String accountId = args[ACCOUNT_ID]; final String accountSecret = args[ACCOUNT_SECRET]; final String version = args[VERSION]; final String s3Path = "apk/" + instance + "/" + file.getName(); final String s3Url = "http://akvoflow.s3.amazonaws.com/apk/" + instance + '/' + file.getName(); final String host = instance + ".appspot.com"; try { uploadS3(accessKey, secretKey, s3Path, file); updateVersion(host, accountId, accountSecret, s3Url, version, getMD5Checksum(file)); } catch (AmazonServiceException ase) { System.err .println("Caught an AmazonServiceException, which means your request made it " + "to Amazon S3, but was rejected with an error response for some reason."); System.err.println("Error Message: " + ase.getMessage()); System.err.println("HTTP Status Code: " + ase.getStatusCode()); System.err.println("AWS Error Code: " + ase.getErrorCode()); System.err.println("Error Type: " + ase.getErrorType()); System.err.println("Request ID: " + ase.getRequestId()); } catch (AmazonClientException ace) { System.err .println("Caught an AmazonClientException, which means the client encountered " + "a serious internal problem while trying to communicate with S3, " + "such as not being able to access the network."); System.err.println("Error Message: " + ace.getMessage()); } catch (IOException e) { System.err.println("Error updating APK version in GAE"); e.printStackTrace(); } } private static void uploadS3(String accessKey, String secretKey, String s3Path, File file) throws AmazonServiceException, AmazonClientException { BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); AmazonS3 s3 = new AmazonS3Client(credentials); PutObjectRequest putRequest = new PutObjectRequest(BUCKET_NAME, s3Path, file); ObjectMetadata metadata = new ObjectMetadata(); // set content type as android package file metadata.setContentType("application/vnd.android.package-archive"); // set content length to length of file metadata.setContentLength(file.length()); // set access to public putRequest.setMetadata(metadata); putRequest.setCannedAcl(CannedAccessControlList.PublicRead); // try to put the apk in S3 PutObjectResult result = s3.putObject(putRequest); System.out.println("Apk uploaded successfully, with result ETag " + result.getETag()); } private static void updateVersion(String host, String accountId, String accountSecret, String url, String version, String md5) throws IOException { RemoteApiOptions options = new RemoteApiOptions().server(host, 443) .useServiceAccountCredential(accountId, accountSecret); RemoteApiInstaller installer = new RemoteApiInstaller(); installer.install(options); try { DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); Entity e = new Entity("DeviceApplication"); e.setProperty("appCode", "flowapp"); e.setProperty("deviceType", "androidPhone"); e.setProperty("version", version); e.setProperty("fileName", url); e.setProperty("md5Checksum", md5); final Date date = new Date();// use the same timestampt e.setProperty("createdDateTime", date); e.setProperty("lastUpdateDateTime", date); ds.put(e); } finally { installer.uninstall(); } System.out.println("New APK version successfully stored in GAE"); } private static String getMD5Checksum(File file) { InputStream in = null; MessageDigest md; try { md = MessageDigest.getInstance("MD5"); in = new BufferedInputStream(new FileInputStream(file)); byte[] buffer = new byte[8192]; int read; while ((read = in.read(buffer)) != -1) { md.update(buffer, 0, read); } byte[] rawHash = md.digest(); StringBuilder builder = new StringBuilder(); for (byte b : rawHash) { builder.append(String.format("%02x", b)); } return builder.toString(); } catch (NoSuchAlgorithmException e) { System.out.println(e.getMessage()); } catch (IOException e) { System.out.println(e.getMessage()); } finally { try { in.close(); } catch (Exception ignored) {} } return null; } }