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