package com.amazonaws.eclipse.codedeploy.deploy.util; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; import org.apache.commons.io.FileUtils; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import com.amazonaws.eclipse.codedeploy.CodeDeployPlugin; import com.amazonaws.eclipse.codedeploy.deploy.wizard.model.DeployProjectToCodeDeployWizardDataModel; import com.amazonaws.eclipse.core.AwsToolkitCore; import com.amazonaws.eclipse.core.regions.ServiceAbbreviations; import com.amazonaws.services.codedeploy.AmazonCodeDeploy; import com.amazonaws.services.codedeploy.model.BundleType; import com.amazonaws.services.codedeploy.model.CreateDeploymentRequest; import com.amazonaws.services.codedeploy.model.CreateDeploymentResult; import com.amazonaws.services.codedeploy.model.RevisionLocation; import com.amazonaws.services.codedeploy.model.RevisionLocationType; import com.amazonaws.services.codedeploy.model.S3Location; import com.amazonaws.services.s3.AmazonS3; public class DeployUtils { /** * @return the deployment ID */ public static String createDeployment( DeployProjectToCodeDeployWizardDataModel dataModel, IProgressMonitor progressMonitor) { CodeDeployPlugin.getDefault().logInfo( "Preparing for deployment: " + dataModel.toString()); /* * (1) Export application archive WAR file */ final IProject project = dataModel.getProject(); String uuid = UUID.randomUUID().toString(); String tempDirName = dataModel.getApplicationName() + "-" + uuid + "-deployment-dir"; String zipFileName = dataModel.getApplicationName() + "-" + uuid + ".zip"; File tempDir = new File( new File(System.getProperty("java.io.tmpdir")), tempDirName); File archiveContentDir = new File( tempDir, "archive-content"); progressMonitor.subTask("Export project to WAR file..."); String warFileRelativePath = dataModel.getTemplateModel() .getWarFileExportLocationWithinDeploymentArchive(); CodeDeployPlugin.getDefault().logInfo( "Preparing to export project [" + project.getName() + "] to a WAR file [" + new File(archiveContentDir, warFileRelativePath).getAbsolutePath() + "]."); File warFile = WTPWarUtils.exportProjectToWar( project, new Path(archiveContentDir.getAbsolutePath()), warFileRelativePath).toFile(); CodeDeployPlugin.getDefault().logInfo( "WAR file created at [" + warFile.getAbsolutePath() + "]"); progressMonitor.worked(10); progressMonitor.subTask("Add app-spec file and all the deployment event hooks..."); try { addAppSpecFileAndEventHooks(archiveContentDir, dataModel); } catch (IOException e) { CodeDeployPlugin.getDefault().reportException( "Error when adding app-spec fild and deployment event hooks.", e); } progressMonitor.worked(5); progressMonitor.subTask("Create the ZIP file including all the deployment artifacts..."); File zipArchive = new File(tempDir, zipFileName); CodeDeployPlugin.getDefault().logInfo( "Preparing to bundle project artifacts into a zip file [" + zipArchive.getAbsolutePath() + "]."); try { ZipUtils.createZipFileOfDirectory(archiveContentDir, zipArchive); } catch (IOException e) { CodeDeployPlugin.getDefault().reportException( "Error when creating zip archive file for the deployment.", e); } CodeDeployPlugin.getDefault().logInfo( "Zip file created at [" + zipArchive.getAbsolutePath() + "]."); progressMonitor.worked(15); /* * (2) Upload to S3 */ String bucketName = dataModel.getBucketName(); String keyName = zipArchive.getName(); AmazonS3 s3Client = AwsToolkitCore.getClientFactory() .getS3ClientByEndpoint("https://s3.amazonaws.com/"); progressMonitor.subTask("Upload ZIP file to S3..."); CodeDeployPlugin.getDefault().logInfo( "Uploading zip file to S3 bucket [" + bucketName + "]."); s3Client.putObject(bucketName, keyName, zipArchive); CodeDeployPlugin.getDefault().logInfo( "Upload succeed. [s3://" + bucketName + "/" + keyName + "]"); progressMonitor.worked(30); /* * (3) CreateDeployment */ progressMonitor.subTask("Initiate deployment..."); CodeDeployPlugin.getDefault().logInfo( "Making CreateDeployment API call..."); String endpoint = dataModel.getRegion().getServiceEndpoints() .get(ServiceAbbreviations.CODE_DEPLOY); AmazonCodeDeploy client = AwsToolkitCore.getClientFactory() .getCodeDeployClientByEndpoint(endpoint); CreateDeploymentResult result = client.createDeployment(new CreateDeploymentRequest() .withApplicationName(dataModel.getApplicationName()) .withDeploymentGroupName(dataModel.getDeploymentGroupName()) .withDeploymentConfigName(dataModel.getDeploymentConfigName()) .withIgnoreApplicationStopFailures(dataModel.isIgnoreApplicationStopFailures()) .withRevision(new RevisionLocation() .withRevisionType(RevisionLocationType.S3) .withS3Location(new S3Location() .withBucket(bucketName) .withKey(keyName) .withBundleType(BundleType.Zip) )) .withDescription("Deployment created from AWS Eclipse plugin") ); CodeDeployPlugin.getDefault().logInfo( "Deployment submitted. Deployment ID [" + result.getDeploymentId() + "]"); progressMonitor.worked(10); return result.getDeploymentId(); } private static void addAppSpecFileAndEventHooks(File targetBaseDir, final DeployProjectToCodeDeployWizardDataModel deployDataModel) throws IOException { File templateCopySourceRoot = deployDataModel.getTemplateModel() .getResolvedTemplateBasedir(); copyDirectoryWithTransformationHandler(templateCopySourceRoot, targetBaseDir, new FileTransformationHandler() { public void copyFromFileToFile(File src, File target) throws IOException { String srcContent = FileUtils.readFileToString(src); String transformedContent = substituteUserConfiguration( srcContent, deployDataModel.getTemplateParameterValues()); FileUtils.writeStringToFile(target, transformedContent); } }); } private static String substituteUserConfiguration(String originalContent, Map<String, String> paramAnchorTextAndValues) { for (Entry<String, String> entry : paramAnchorTextAndValues.entrySet()) { String anchorText = entry.getKey(); String value = entry.getValue(); originalContent = originalContent.replace(anchorText, value); } return originalContent; } private static void copyDirectoryWithTransformationHandler(File srcDir, File destDir, FileTransformationHandler handler) throws IOException { if (destDir.exists()) { if (destDir.isDirectory() == false) { throw new IOException("Destination '" + destDir + "' exists but is not a directory"); } } else { if (destDir.mkdirs() == false) { throw new IOException("Destination '" + destDir + "' directory cannot be created"); } } if (destDir.canWrite() == false) { throw new IOException("Destination '" + destDir + "' cannot be written to"); } // recurse File[] files = srcDir.listFiles(); if (files == null) { // null if security restricted throw new IOException("Failed to list contents of " + srcDir); } for (int i = 0; i < files.length; i++) { File copiedFile = new File(destDir, files[i].getName()); if (files[i].isDirectory()) { copyDirectoryWithTransformationHandler(files[i], copiedFile, handler); } else { handler.copyFromFileToFile(files[i], copiedFile); } } } private interface FileTransformationHandler { void copyFromFileToFile(File src, File target) throws IOException; } }