1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package com.jcabi.beanstalk.maven.plugin;
31
32 import com.amazonaws.auth.AWSCredentials;
33 import com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalk;
34 import com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalkClient;
35 import com.amazonaws.services.s3.AmazonS3Client;
36 import com.jcabi.aspects.Tv;
37 import com.jcabi.log.Logger;
38 import java.io.File;
39 import java.io.IOException;
40 import java.util.concurrent.TimeUnit;
41 import java.util.zip.ZipFile;
42 import org.apache.maven.plugin.AbstractMojo;
43 import org.apache.maven.plugin.MojoFailureException;
44 import org.apache.maven.settings.Settings;
45 import org.jfrog.maven.annomojo.annotations.MojoParameter;
46 import org.slf4j.impl.StaticLoggerBinder;
47
48
49
50
51
52
53
54
55
56 abstract class AbstractBeanstalkMojo extends AbstractMojo {
57
58
59
60 @MojoParameter(
61 expression = "${settings}",
62 required = true,
63 readonly = true,
64 description = "Maven settings.xml reference"
65 )
66 private transient Settings settings;
67
68
69
70
71 @MojoParameter(
72 defaultValue = "false",
73 required = false,
74 description = "Skips execution"
75 )
76 private transient boolean skip;
77
78
79
80
81 @MojoParameter(
82 defaultValue = "aws.amazon.com",
83 required = false,
84 description = "ID of the server to deploy to, from settings.xml"
85 )
86 private transient String server;
87
88
89
90
91 @MojoParameter(
92 required = true,
93 description = "EBT application name, environment name, and CNAME"
94 )
95 private transient String name;
96
97
98
99
100 @MojoParameter(
101 required = true,
102 description = "Amazon S3 bucket name where to upload WAR file"
103 )
104 private transient String bucket;
105
106
107
108
109 @MojoParameter(
110 required = true,
111 description = "Amazon S3 bucket key where to upload WAR file"
112 )
113 private transient String key;
114
115
116
117
118 @MojoParameter(
119 required = true,
120 description = "Amazon Elastic Beanstalk configuration template name"
121 )
122 private transient String template;
123
124
125
126
127
128 @MojoParameter(
129 defaultValue = "${project.build.directory}/${project.build.finalName}.war",
130 required = false,
131 description = "Location of .WAR file to deploy"
132 )
133 private transient File war;
134
135
136
137
138
139 public void setSkip(final boolean skp) {
140 this.skip = skp;
141 }
142
143
144
145
146 @Override
147 public void execute() throws MojoFailureException {
148 StaticLoggerBinder.getSingleton().setMavenLog(this.getLog());
149 if (this.skip) {
150 Logger.info(this, "execution skipped because of 'skip' option");
151 return;
152 }
153 if (!this.war.exists()) {
154 throw new MojoFailureException(
155 String.format("WAR file '%s' doesn't exist", this.war)
156 );
157 }
158 try {
159 new WarFile(new ZipFile(this.war)).checkEbextensionsValidity();
160 } catch (final IOException ex) {
161 throw new MojoFailureException(
162 ".ebextensions validity check failed",
163 ex
164 );
165 }
166 final AWSCredentials creds = this.createServerCredentials();
167 final AWSElasticBeanstalk ebt = new AWSElasticBeanstalkClient(creds);
168 try {
169 this.exec(
170 new Application(ebt, this.name),
171 new OverridingVersion(
172 ebt,
173 this.name,
174 new Bundle.Safe(
175 new OverridingBundle(
176 new AmazonS3Client(creds),
177 this.bucket,
178 this.key,
179 this.war
180 )
181 )
182 ),
183 this.template
184 );
185 } catch (final DeploymentException ex) {
186 throw new MojoFailureException("failed to deploy", ex);
187 } finally {
188 ebt.shutdown();
189 }
190 }
191
192
193
194
195
196
197 protected ServerCredentials createServerCredentials()
198 throws MojoFailureException {
199 return new ServerCredentials(
200 this.settings,
201 this.server
202 );
203 }
204
205
206
207
208
209
210
211 protected abstract void exec(final Application app,
212 final Version version, final String tmpl);
213
214
215
216
217
218 protected void postMortem(final Environment env) {
219 Logger.error(this, "Failed to deploy to '%s'", env);
220 if (!env.terminated()) {
221 Logger.error(
222 this,
223 "TAIL report should explain the cause of failure:"
224 );
225 this.log(env.tail().split("\n"));
226 }
227 Logger.error(this, "Latest EBT events (in reverse order):");
228 this.log(env.events());
229 env.terminate();
230 }
231
232
233
234
235
236
237 protected boolean isGreen(final Environment env) {
238 boolean green = env.green();
239 final long start = System.currentTimeMillis();
240 while (!green) {
241 final long age = System.currentTimeMillis() - start;
242 if (age > TimeUnit.MINUTES.toMillis(Tv.FIFTEEN)) {
243 Logger.warn(this, "Waiting for %[ms]s, time to give up", age);
244 break;
245 }
246 Logger.warn(
247 this,
248 "%s is not GREEN yet, let's wait another 15 second...", env
249 );
250 try {
251 TimeUnit.SECONDS.sleep(Tv.FIFTEEN);
252 } catch (final InterruptedException ex) {
253 Thread.currentThread().interrupt();
254 throw new DeploymentException(ex);
255 }
256 green = env.green();
257 }
258 return green;
259 }
260
261
262
263
264
265 private void log(final String[] lines) {
266 for (final String line : lines) {
267 Logger.info(this, ">> %s", line);
268 }
269 }
270 }