/* * Copyright 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 com.amazonaws.ant.opsworks; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.apache.tools.ant.TaskContainer; import org.apache.tools.ant.UnknownElement; import com.amazonaws.ant.AWSAntTask; import com.amazonaws.services.opsworks.AWSOpsWorksClient; import com.amazonaws.services.opsworks.model.Deployment; import com.amazonaws.services.opsworks.model.DescribeDeploymentsRequest; public class IncrementalDeploymentTask extends AWSAntTask { private LinkedList<DeploymentGroup> deploymentGroups = new LinkedList<DeploymentGroup>(); /** * Allows you to add any number of nested DeploymentGroup elements to this * task. * * @param deploymentGroup * A preconfigured DeploymentGroup object. */ public void addConfiguredDeploymentGroup(DeploymentGroup deploymentGroup) { deploymentGroups.add(deploymentGroup); } /** * Deploys each deployment in each deployment group, waits for the * deployments to succeed, then deploys the next group until finished. */ public void execute() { AWSOpsWorksClient client = getOrCreateClient(AWSOpsWorksClient.class); for (DeploymentGroup deploymentGroup : deploymentGroups) { deploymentGroup.setClient(client); deploymentGroup.deployApps(); } } /** * A class to be used as a nested element. Use to specify groups of * deployment tasks sequentially, where the second group must wait for the * first group to succeed in order to deploy, etc. */ public static class DeploymentGroup implements TaskContainer { private List<Task> deployAppTasks = new LinkedList<Task>(); private Set<String> deploymentIds = new HashSet<String>(); private AWSOpsWorksClient client; /** * Allows you to add any number of nested DeployAppTask deployment * elements to this group. Fails if you try to add anything other than a * DeployAppTask element. * * @param task * A preconfigured DeployApptask object. */ public void addTask(Task task) { try { deployAppTasks.add(task); } catch (Exception e) { throw new BuildException( "Only deploy-opsworks-app is supported " + e.getMessage()); } } public DeploymentGroup() { // required by Ant } /** * Set the client to use to access AWS OpsWorks. * * @param client * The client to use to access AWS OpsWorks. */ public void setClient(AWSOpsWorksClient client) { this.client = client; } /** * Deploys all apps in this deployment group, then waits for all the * deployments in the group to succeed. Deployments in a group will run * in parallel. */ public void deployApps() { for (Task deployAppTask : deployAppTasks) { // This is in case of a rare bug that occurs in some JVM implementations if (deployAppTask instanceof UnknownElement) { deployAppTask.maybeConfigure(); deployAppTask = ((UnknownElement) deployAppTask).getTask(); } if (!deployAppTask.getTaskName().equals("deploy-opsworks-app")) { throw new BuildException( "Only <deploy-opsworks-app> elements are supported"); } deployAppTask.execute(); deploymentIds.add(deployAppTask.getDescription()); } try { waitForDeploymentGroupToSucceed(deploymentIds, client); } catch (InterruptedException e) { throw new BuildException(e.getMessage(), e); } } /** * Waits for a deployment group to succeed * * @param deploymentIds * The set of the IDs of the deployments in the group * @param client * The client to use to access AWSOpsWorks * @throws InterruptedException * If the thread is interrupted */ public void waitForDeploymentGroupToSucceed(Set<String> deploymentIds, AWSOpsWorksClient client) throws InterruptedException { int count = 0; while (true) { if (deploymentIds.isEmpty()) { return; } Thread.sleep(1000 * 10); if (count++ > 100) { throw new BuildException( "Deployment never failed or succeeded"); } List<Deployment> deployments = client.describeDeployments( new DescribeDeploymentsRequest() .withDeploymentIds(deploymentIds)) .getDeployments(); for (Deployment deployment : deployments) { String status = deployment.getStatus(); System.out.println(deployment.getDeploymentId() + " : " + status); if (status.equalsIgnoreCase("failed")) { throw new BuildException("Deployment " + deployment.getDeploymentId() + " failed"); } else if (status.equalsIgnoreCase("successful")) { deploymentIds.remove(deployment.getDeploymentId()); } } } } } }