View Javadoc
1   /*
2    * Copyright (c) 2016 ingenieux Labs
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package br.com.ingenieux.mojo.beanstalk.version;
18  
19  import com.amazonaws.services.elasticbeanstalk.model.ApplicationVersionDescription;
20  import com.amazonaws.services.elasticbeanstalk.model.DeleteApplicationVersionRequest;
21  import com.amazonaws.services.elasticbeanstalk.model.DescribeApplicationVersionsRequest;
22  import com.amazonaws.services.elasticbeanstalk.model.DescribeApplicationVersionsResult;
23  import com.amazonaws.services.elasticbeanstalk.model.DescribeEnvironmentsRequest;
24  import com.amazonaws.services.elasticbeanstalk.model.DescribeEnvironmentsResult;
25  import com.amazonaws.services.elasticbeanstalk.model.EnvironmentDescription;
26  
27  import org.apache.commons.lang.builder.CompareToBuilder;
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugin.MojoFailureException;
30  import org.apache.maven.plugins.annotations.Mojo;
31  import org.apache.maven.plugins.annotations.Parameter;
32  
33  import java.util.ArrayList;
34  import java.util.Collections;
35  import java.util.Comparator;
36  import java.util.Date;
37  import java.util.List;
38  import java.util.ListIterator;
39  import java.util.regex.Pattern;
40  
41  import br.com.ingenieux.mojo.beanstalk.AbstractBeanstalkMojo;
42  
43  /**
44   * Deletes application versions, either by count and/or by date old
45   *
46   * @since 0.2.2
47   */
48  @Mojo(name = "clean-previous-versions")
49  public class CleanPreviousVersionsMojo extends AbstractBeanstalkMojo {
50  
51    /**
52     * Beanstalk Application Name
53     */
54    @Parameter(property = "beanstalk.applicationName", defaultValue = "${project.artifactId}", required = true)
55    String applicationName;
56  
57    /**
58     * Delete the source bundle?
59     */
60    @Parameter(property = "beanstalk.deleteSourceBundle", defaultValue = "false")
61    boolean deleteSourceBundle;
62  
63    /**
64     * How many versions to keep?
65     */
66    @Parameter(property = "beanstalk.versionsToKeep")
67    Integer versionsToKeep;
68  
69    /**
70     * How many versions to keep?
71     */
72    @Parameter(property = "beanstalk.daysToKeep")
73    Integer daysToKeep;
74  
75    /**
76     * Filter application version list to examine for cleaning based on java.util.regex.Pattern
77     * string.
78     */
79    @Parameter(property = "beanstalk.cleanFilter")
80    String cleanFilter;
81  
82    /**
83     * Simulate deletion changing algorithm?
84     */
85    @Parameter(property = "beanstalk.dryRun", defaultValue = "true")
86    boolean dryRun;
87  
88    private int deletedVersionsCount;
89  
90    @Override
91    protected Object executeInternal() throws MojoExecutionException, MojoFailureException {
92      boolean bVersionsToKeepDefined = (null != versionsToKeep);
93      boolean bDaysToKeepDefined = (null != daysToKeep);
94  
95      if (!(bVersionsToKeepDefined ^ bDaysToKeepDefined)) {
96        throw new MojoFailureException("Declare either versionsToKeep or daysToKeep, but not both nor none!");
97      }
98  
99      DescribeApplicationVersionsRequest describeApplicationVersionsRequest = new DescribeApplicationVersionsRequest().withApplicationName(applicationName);
100 
101     DescribeApplicationVersionsResult appVersions = getService().describeApplicationVersions(describeApplicationVersionsRequest);
102 
103     DescribeEnvironmentsResult environments = getService().describeEnvironments(new DescribeEnvironmentsRequest().withApplicationName(applicationName));
104 
105     List<ApplicationVersionDescription> appVersionList = new ArrayList<ApplicationVersionDescription>(appVersions.getApplicationVersions());
106 
107     deletedVersionsCount = 0;
108 
109     for (EnvironmentDescription d : environments.getEnvironments()) {
110       boolean bActiveEnvironment = (d.getStatus().equals("Running") || d.getStatus().equals("Launching") || d.getStatus().equals("Ready"));
111 
112       for (ListIterator<ApplicationVersionDescription> appVersionIterator = appVersionList.listIterator(); appVersionIterator.hasNext(); ) {
113         ApplicationVersionDescription appVersion = appVersionIterator.next();
114 
115         boolean bMatchesVersion = appVersion.getVersionLabel().equals(d.getVersionLabel());
116 
117         if (bActiveEnvironment && bMatchesVersion) {
118           getLog().info("VersionLabel " + appVersion.getVersionLabel() + " is bound to environment " + d.getEnvironmentName() + " - Skipping it");
119 
120           appVersionIterator.remove();
121         }
122       }
123     }
124 
125     filterAppVersionListByVersionLabelPattern(appVersionList, cleanFilter);
126 
127     Collections.sort(
128         appVersionList,
129         new Comparator<ApplicationVersionDescription>() {
130           @Override
131           public int compare(ApplicationVersionDescription o1, ApplicationVersionDescription o2) {
132             return new CompareToBuilder().append(o1.getDateUpdated(), o2.getDateUpdated()).toComparison();
133           }
134         });
135 
136     if (bDaysToKeepDefined) {
137       Date now = new Date();
138 
139       for (ApplicationVersionDescription d : appVersionList) {
140         long delta = now.getTime() - d.getDateUpdated().getTime();
141 
142         delta /= 1000;
143         delta /= 86400;
144 
145         boolean shouldDeleteP = (delta > daysToKeep);
146 
147         if (getLog().isDebugEnabled()) {
148           getLog().debug("Version " + d.getVersionLabel() + " was from " + delta + " days ago. Should we delete? " + shouldDeleteP);
149         }
150 
151         if (shouldDeleteP) {
152           deleteVersion(d);
153         }
154       }
155     } else {
156       while (appVersionList.size() > versionsToKeep) {
157         deleteVersion(appVersionList.remove(0));
158       }
159     }
160 
161     getLog().info("Deleted " + deletedVersionsCount + " versions.");
162 
163     return null;
164   }
165 
166   void deleteVersion(ApplicationVersionDescription versionToRemove) {
167     getLog().info("Must delete version: " + versionToRemove.getVersionLabel());
168 
169     DeleteApplicationVersionRequest req =
170         new DeleteApplicationVersionRequest()
171             .withApplicationName(versionToRemove.getApplicationName()) //
172             .withDeleteSourceBundle(deleteSourceBundle) //
173             .withVersionLabel(versionToRemove.getVersionLabel());
174 
175     if (!dryRun) {
176       getService().deleteApplicationVersion(req);
177       deletedVersionsCount++;
178     }
179   }
180 
181   void filterAppVersionListByVersionLabelPattern(List<ApplicationVersionDescription> appVersionList, String patternString) {
182     if (patternString == null) {
183       return;
184     }
185 
186     getLog().info("Filtering versions with pattern : " + patternString);
187 
188     Pattern p = Pattern.compile(patternString);
189     for (ListIterator<ApplicationVersionDescription> appVersionIterator = appVersionList.listIterator(); appVersionIterator.hasNext(); ) {
190 
191       if (!p.matcher(appVersionIterator.next().getVersionLabel()).matches()) {
192         appVersionIterator.remove();
193       }
194     }
195   }
196 }