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.env;
18  
19  import com.amazonaws.services.elasticbeanstalk.model.EnvironmentDescription;
20  
21  import org.apache.commons.lang.Validate;
22  import org.apache.maven.plugin.AbstractMojoExecutionException;
23  import org.apache.maven.plugins.annotations.Mojo;
24  import org.apache.maven.plugins.annotations.Parameter;
25  
26  import java.util.Collection;
27  
28  import br.com.ingenieux.mojo.beanstalk.AbstractBeanstalkMojo;
29  import br.com.ingenieux.mojo.beanstalk.cmd.env.swap.SwapCNamesCommand;
30  import br.com.ingenieux.mojo.beanstalk.cmd.env.swap.SwapCNamesContext;
31  import br.com.ingenieux.mojo.beanstalk.cmd.env.swap.SwapCNamesContextBuilder;
32  import br.com.ingenieux.mojo.beanstalk.cmd.env.waitfor.WaitForEnvironmentCommand;
33  import br.com.ingenieux.mojo.beanstalk.cmd.env.waitfor.WaitForEnvironmentContextBuilder;
34  import br.com.ingenieux.mojo.beanstalk.util.EnvironmentHostnameUtil;
35  
36  import static java.lang.String.format;
37  import static org.apache.commons.lang.StringUtils.defaultString;
38  import static org.apache.commons.lang.StringUtils.isBlank;
39  import static org.apache.commons.lang.StringUtils.isNotBlank;
40  
41  /**
42   * Lists the available solution stacks
43   *
44   * See the docs for the <a href= "http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_SwapEnvironmentCNAMEs.html"
45   * >SwapEnvironmentCNAMEs API</a> call.
46   *
47   * @author Aldrin Leal
48   * @since 0.2.3
49   */
50  @Mojo(name = "swap-environment-cnames")
51  public class SwapEnvironmentCnamesMojo extends AbstractBeanstalkMojo {
52  
53    /**
54     * Beanstalk Application Name
55     */
56    @Parameter(property = "beanstalk.applicationName", defaultValue = "${project.artifactId}", required = true)
57    String applicationName;
58  
59    /**
60     * EnvironmentRef of source environment
61     */
62    @Parameter(property = "beanstalk.sourceEnvironmentRef")
63    String sourceEnvironmentRef;
64  
65    /**
66     * EnvironmentRef of target environment
67     */
68    @Parameter(property = "beanstalk.targetEnvironmentRef")
69    String targetEnvironmentRef;
70  
71    /**
72     * cname of source environment
73     */
74    @Parameter(property = "beanstalk.sourceEnvironmentCNamePrefix")
75    String sourceEnvironmentCNamePrefix;
76  
77    /**
78     * cname of target environment
79     */
80    @Parameter(property = "beanstalk.targetEnvironmentCNamePrefix")
81    String targetEnvironmentCNamePrefix;
82  
83    boolean nonBlank(String... args) {
84      for (String a : args) if (isBlank(a)) return false;
85  
86      return true;
87    }
88  
89    @Override
90    protected Object executeInternal() throws AbstractMojoExecutionException {
91      SwapCNamesContext context;
92  
93      if (nonBlank(sourceEnvironmentRef, targetEnvironmentRef)) {
94        EnvironmentDescription e0 =
95            findOnly(
96                new WaitForEnvironmentCommand(this)
97                    .lookupInternal(
98                        new WaitForEnvironmentContextBuilder().withApplicationName(applicationName).withEnvironmentRef(sourceEnvironmentRef).build()));
99  
100       EnvironmentDescription e1 =
101           findOnly(
102               new WaitForEnvironmentCommand(this)
103                   .lookupInternal(
104                       new WaitForEnvironmentContextBuilder().withApplicationName(applicationName).withEnvironmentRef(targetEnvironmentRef).build()));
105 
106       Validate.isTrue(isNotBlank(e0.getCNAME()), format("Environment '%s' must be non-worker (thus having a cname)", e1.getEnvironmentId()));
107       Validate.isTrue(isNotBlank(e1.getCNAME()), format("Environment '%s' must be non-worker (thus having a cname)", e1.getEnvironmentId()));
108 
109       context =
110           SwapCNamesContextBuilder.swapCNamesContext() //
111               .withSourceEnvironmentId(e0.getEnvironmentId()) //
112               .withDestinationEnvironmentId(e1.getEnvironmentId()) //
113               .build();
114     } else if (nonBlank(sourceEnvironmentCNamePrefix, targetEnvironmentCNamePrefix)) {
115       sourceEnvironmentCNamePrefix = defaultString(sourceEnvironmentCNamePrefix);
116       targetEnvironmentCNamePrefix = defaultString(targetEnvironmentCNamePrefix);
117 
118       Validate.isTrue(
119           sourceEnvironmentCNamePrefix.matches("[\\p{Alnum}\\-]{4,63}"), "Invalid Source Environment CName Prefix: " + sourceEnvironmentCNamePrefix);
120       Validate.isTrue(
121           targetEnvironmentCNamePrefix.matches("[\\p{Alnum}\\-]{4,63}"), "Invalid Target Environment CName Prefix: " + targetEnvironmentCNamePrefix);
122 
123       EnvironmentDescription sourceEnvironment =
124           lookupEnvironment(applicationName, EnvironmentHostnameUtil.ensureSuffix(sourceEnvironmentCNamePrefix, getRegion()));
125       EnvironmentDescription targetEnvironment =
126           lookupEnvironment(applicationName, EnvironmentHostnameUtil.ensureSuffix(targetEnvironmentCNamePrefix, getRegion()));
127 
128       // TODO: Why 'destination' instead of 'target'? Make it consistent
129       context =
130           SwapCNamesContextBuilder.swapCNamesContext() //
131               .withSourceEnvironmentId(sourceEnvironment.getEnvironmentId()) //
132               .withDestinationEnvironmentId(targetEnvironment.getEnvironmentId()) //
133               .build();
134     } else {
135       throw new IllegalArgumentException("You must supply either {source,target}EnvironmentCNamePrefix or {source,target}EnvironmentRef");
136     }
137 
138     SwapCNamesCommandd/env/swap/SwapCNamesCommand.html#SwapCNamesCommand">SwapCNamesCommand command = new SwapCNamesCommand(this);
139 
140     return command.execute(context);
141   }
142 
143   private EnvironmentDescription findOnly(Collection<EnvironmentDescription> environmentDescriptions) {
144     Validate.isTrue(1 == environmentDescriptions.size(), "More than one environment matches spec");
145 
146     return environmentDescriptions.iterator().next();
147   }
148 }