/** * Copyright 2013 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 awslabs.lab51; import java.io.File; import java.io.FileInputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.UUID; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.AWSCredentialsProviderChain; import com.amazonaws.auth.EnvironmentVariableCredentialsProvider; import com.amazonaws.auth.InstanceProfileCredentialsProvider; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; import com.amazonaws.services.dynamodbv2.model.AttributeValue; import com.amazonaws.services.dynamodbv2.model.TableDescription; import com.amazonaws.services.s3.AmazonS3Client; /** * Project: Lab5.1 */ public class Lab51 { private ILabCode labCode = new StudentCode(this); private IOptionalLabCode optionalLabCode = new StudentCode(this); private List<String> statusLog = new ArrayList<String>(); private List<String> imageListRows = new ArrayList<String>(); private List<String> imageNames = new ArrayList<String>(); private InstanceIdentity instance = new InstanceIdentity(); private AWSCredentials credentials; // Create a custom credentials provider chain. private AWSCredentialsProvider credsProvider = new AWSCredentialsProviderChain( new EnvironmentVariableCredentialsProvider(), new InstanceProfileCredentialsProvider()); public Lab51() { // Add our images to the list. imageNames.add("icons/dynamodb.png"); imageNames.add("icons/ec2.png"); imageNames.add("icons/elasticbeanstalk.png"); imageNames.add("icons/iam.png"); imageNames.add("icons/s3.png"); imageNames.add("icons/sqs.png"); // DECOY IMAGE imageNames.add("decoy/decoy.png"); try { credentials = credsProvider.getCredentials(); } catch (Exception ex) { logMessageToPage(ex.getMessage()); return; } finally { if (credentials==null) { logMessageToPage("No credentials found."); return; } } // Import custom settings, if provided. Source: Our custom config to ElasticBeanstalk. prepSettings(); // Now that our objects are created, let's inspect the values and provide additional defaults where needed. if (System.getProperty("SESSIONTABLE") == null || System.getProperty("SESSIONTABLE").isEmpty()) { logMessageToPage("SESSIONTABLE wasn't defined. Using default value 'imageindex'"); System.setProperty("SESSIONTABLE", "imageindex"); } if (System.getProperty("REGION") == null || System.getProperty("REGION").isEmpty()) { logMessageToPage("REGION wasn't defined. Using default value 'us-east-1'"); System.setProperty("REGION", "us-east-1"); } if (System.getProperty("PARAM3") == null || System.getProperty("PARAM3").isEmpty()) { logMessageToPage("PARAM3 wasn't defined. Using default value 'icons'"); System.setProperty("PARAM3", "icons"); } } public void syncImages() { try { String tableName = System.getProperty("SESSIONTABLE"); AmazonDynamoDBClient dynamoDbClient = labCode.createDynamoDbClient(credentials); TableDescription tableDescription = optionalLabCode.getTableDescription(dynamoDbClient, tableName); if (tableDescription == null) { logMessageToPage("No table found. Creating it."); optionalLabCode.buildTable(dynamoDbClient, tableName); tableDescription = optionalLabCode.getTableDescription(dynamoDbClient, tableName); } // We have a table. Let's see if it's valid. if (!optionalLabCode.validateSchema(tableDescription)) { // It's not valid, so let's rebuild it. logMessageToPage("Table schema is incorrect. Dropping table and rebuilding it."); optionalLabCode.deleteTable(dynamoDbClient, tableName); optionalLabCode.buildTable(dynamoDbClient, tableName); } // Valid now, so let's look for our images. If they're not in DynamoDB, we need to add them to DynamoDB *and* S3 List<String> missingImages = new ArrayList<String>(); for (String image : imageNames) { if (!optionalLabCode.isImageInDynamo(dynamoDbClient, tableName, image)) { // It's not there, so add it to the list of missing images. missingImages.add(image); } } // If our list of images is missing anything, be sure to add it before formatting them for the page. if (missingImages.size() > 0) { String bucketName = "awslabj" + UUID.randomUUID().toString().substring(0, 8); logMessageToPage("Adding images to S3 (%s) and DynamoDB", bucketName); // Add the missing images now. AmazonS3Client s3Client = labCode.createS3Client(credentials); // Create the bucket first // If the region is other than us-east-1, we need to specify a regional constraint for the // create bucket call. String region = System.getProperty("REGION"); if (region.equals("us-east-1")) { s3Client.createBucket(bucketName); } else { s3Client.createBucket(bucketName, com.amazonaws.services.s3.model.Region.fromValue(region)); } String rootPath = Lab51.class.getResource("/").getFile(); for (String image : missingImages) { String filePath = rootPath + image; if (new File(filePath).exists()) { optionalLabCode.addImage(dynamoDbClient, tableName, s3Client, bucketName, image, filePath); } else { logMessageToPage("File not found on disk: %s", filePath); } } } } catch (Exception ex) { logMessageToPage("syncImages() error: [%s] %s", ex.getClass().getName(), ex.getMessage()); } } public String getConfigAsHtml() { StringBuilder sb = new StringBuilder(); sb.append(String.format("<tr><td><b>%s</b> <i>%s</i> </td><td> %s</td></tr>", "SESSIONTABLE", "(table name)", System.getProperty("SESSIONTABLE"))); sb.append(String.format("<tr><td><b>%s</b> <i>%s</i> </td><td> %s</td></tr>", "REGION", "(target region)", System.getProperty("REGION"))); sb.append(String.format("<tr><td><b>%s</b> <i>%s</i> </td><td> %s</td></tr>", "PARAM3", "(key prefix)", System.getProperty("PARAM3"))); sb.append(String.format("<tr><td><b>%s</b> </td><td> %s</td></tr>", "runtime.settings", System.getProperty("runtime.settings"))); return sb.toString(); } public String getSysEnvAsHtml() { StringBuilder sb = new StringBuilder(); sb.append(String.format("<tr><td><b>%s</b> </td><td> %s</td></tr>", "EC2 Instance ID", instance.getInstanceId())); sb.append(String.format("<tr><td><b>%s</b> </td><td> %s</td></tr>", "Instance Type", instance.getInstanceType())); sb.append(String.format("<tr><td><b>%s</b> </td><td> %s</td></tr>", "Host Instance Region", instance.getRegion())); sb.append(String.format("<tr><td><b>%s</b> </td><td> %s</td></tr>", "Availability Zone", instance.getAvailabilityZone())); String[] keys = { "PROCESSOR_IDENTIFIER" }; for (String key : keys) { sb.append(String.format("<tr><td><b>%s</b> </td><td> %s</td></tr>", key, System.getenv(key))); } return sb.toString(); } public String getImageListAsHtml() { StringBuilder sb = new StringBuilder(); buildImageList(); for (String imageRow : imageListRows) { sb.append(imageRow); } return sb.toString(); } public String getStatusAsHtml() { StringBuilder sb = new StringBuilder(); String newline = System.getProperty("line.separator"); if (statusLog.size() > 0) { sb.append("<ul>"); for (String status : statusLog) { sb.append(String.format("<li>%s</li>%s", status.contains(newline) ? formatForPage(status) : status, newline)); //sb.append(String.format("<li>%s</li>", status)); // System.lineSeparator())); } sb.append("</ul>"); statusLog.clear(); } return sb.toString(); } /** * Store a message to be logged to the screen when the page renders. * * @param message The message to log. */ public void logMessageToPage(String message) { SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy HH:mm:ss.SS"); statusLog.add(String.format("[%s] %s", sdf.format(new Date()), message)); } /** * Store a message to be logged to the screen when the page renders. * * @param format The format string. * @param args The format string parameters. */ public void logMessageToPage(String format, Object... args) { logMessageToPage(String.format(format, args)); } /** * Adds an image to the web page as a stacked cell. The image specified by the URL parameter is displayed on the * page, and the remaining parameters of the method are displayed beside it. * * @param url The URL for the image to display. * @param bucket The bucket that contains the image file. * @param key The key of the image file in the bucket. */ public void addImageToPage(String url, String bucket, String key) { StringBuilder sb = new StringBuilder(); sb.append("<div class=\"imageblock\"><table><tr>"); sb.append("<td><img src=\"" + url + "\" /></td>"); sb.append("<td><table>"); sb.append("<tr><td><b>Bucket:</b></td><td>" + bucket + "</td></tr>"); sb.append("<tr><td><b>Key:</b></td><td>" + key + "</td></tr>"); sb.append("</table></td></tr></table></div>"); imageListRows.add(sb.toString()); } // If we have a setting for runtime.config it points to a file that contains // information placed there by ElasticBeanstalk per the statements we put in // our custom config file. It adds the name of the DynamoDB table that it // provisioned for us, and the region our application is deployed into (and // running in). private void prepSettings() { String settingsFileName = System.getProperty("runtime.settings"); if (settingsFileName != null && !settingsFileName.isEmpty()) { File settingsFile = new File(settingsFileName); if (settingsFile.exists()) { Properties properties = new Properties(); try { // Take each property from the file and add it to the System properties. properties.load(new FileInputStream(settingsFile)); for (Entry<Object, Object> entry : properties.entrySet()) { System.setProperty((String)entry.getKey(), (String)entry.getValue()); } logMessageToPage("Properties imported from %s", settingsFileName); } catch (Exception ex) { logMessageToPage("Error while loading settings from %s:%s%s", settingsFileName, System.lineSeparator(), ex.getMessage()); return; } } else { logMessageToPage("Settings file was specified but doesn't exist."); } } else { logMessageToPage("No settings file speicified."); } } private String formatForPage(String status) { String temp = status.replaceAll(" ", "  "); temp = temp.replaceAll(System.getProperty("line.separator"), "<br/>"); return String.format("<div>%s</div>", temp); } /** * BuildImageList - Collects the information necessary for displaying the images on the page. * */ private void buildImageList() { imageListRows.clear(); if (credentials != null) { AmazonDynamoDBClient dynamoDbClient = labCode.createDynamoDbClient(credentials); AmazonS3Client s3Client = labCode.createS3Client(credentials); List<Map<String, AttributeValue>> images = labCode.getImageItems(dynamoDbClient); if (images != null) { labCode.addItemsToPage(s3Client, images); } else { logMessageToPage("List of images came back from DynamoDB empty."); } } else { logMessageToPage("Skipped building image list because no credentials were found."); } } }