@@ -73,6 +73,14 @@ public class DeployJob extends MonitorableJob {
73
73
74
74
private static final Logger LOG = LoggerFactory .getLogger (DeployJob .class );
75
75
private static final String bundlePrefix = "bundles" ;
76
+ /**
77
+ * S3 bucket to upload deployment to. If not null, uses {@link OtpServer#s3Bucket}. Otherwise, defaults to
78
+ * {@link DataManager#feedBucket}
79
+ * */
80
+ private final String s3Bucket ;
81
+ private final int targetCount ;
82
+ private int tasksCompleted = 0 ;
83
+ private int totalTasks ;
76
84
77
85
private AmazonEC2 ec2 ;
78
86
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss z" );
@@ -89,6 +97,7 @@ public class DeployJob extends MonitorableJob {
89
97
/** This hides the status field on the parent class, providing additional fields. */
90
98
public DeployStatus status ;
91
99
100
+ private String statusMessage ;
92
101
private int serverCounter = 0 ;
93
102
// private String imageId;
94
103
private String dateString = DATE_FORMAT .format (new Date ());
@@ -105,8 +114,11 @@ public DeployJob(Deployment deployment, String owner, OtpServer otpServer) {
105
114
super (owner , "Deploying " + deployment .name , JobType .DEPLOY_TO_OTP );
106
115
this .deployment = deployment ;
107
116
this .otpServer = otpServer ;
117
+ this .s3Bucket = otpServer .s3Bucket != null ? otpServer .s3Bucket : DataManager .feedBucket ;
108
118
// Use a special subclass of status here that has additional fields
109
119
this .status = new DeployStatus ();
120
+ this .targetCount = otpServer .internalUrl != null ? otpServer .internalUrl .size () : 0 ;
121
+ this .totalTasks = 1 + targetCount ;
110
122
status .message = "Initializing..." ;
111
123
status .built = false ;
112
124
status .numServersCompleted = 0 ;
@@ -118,14 +130,9 @@ public DeployJob(Deployment deployment, String owner, OtpServer otpServer) {
118
130
}
119
131
120
132
public void jobLogic () {
121
- int targetCount = otpServer .internalUrl != null ? otpServer .internalUrl .size () : 0 ;
122
- int totalTasks = 1 + targetCount ;
123
133
if (otpServer .s3Bucket != null ) totalTasks ++;
124
134
// FIXME
125
135
if (otpServer .targetGroupArn != null ) totalTasks ++;
126
- int tasksCompleted = 0 ;
127
- String statusMessage ;
128
-
129
136
try {
130
137
deploymentTempFile = File .createTempFile ("deployment" , ".zip" );
131
138
} catch (IOException e ) {
@@ -155,49 +162,22 @@ public void jobLogic () {
155
162
LOG .info ("Deployment pctComplete = {}" , status .percentComplete );
156
163
status .built = true ;
157
164
158
- // Upload to S3, if applicable
159
- if (otpServer .s3Bucket != null ) {
160
- status .message = "Uploading to S3" ;
161
- status .uploadingS3 = true ;
162
- String key = getS3BundleKey ();
163
- LOG .info ("Uploading deployment {} to s3://{}/{}" , deployment .name , otpServer .s3Bucket , key );
165
+ // Upload to S3, if specifically required by the OTPServer or needed for servers in the target group to fetch.
166
+ if (otpServer .s3Bucket != null || otpServer .targetGroupArn != null ) {
164
167
try {
165
- // PutObjectRequest putObjectRequest = new PutObjectRequest(otpServer.s3Bucket, key, deploymentTempFile).;
166
- TransferManager tx = TransferManagerBuilder .standard ().withS3Client (FeedStore .s3Client ).build ();
167
- final Upload upload = tx .upload (otpServer .s3Bucket , key , deploymentTempFile );
168
-
169
- upload .addProgressListener ((ProgressListener ) progressEvent -> {
170
- status .percentUploaded = upload .getProgress ().getPercentTransferred ();
171
- });
172
-
173
- upload .waitForCompletion ();
174
-
175
- // Shutdown the Transfer Manager, but don't shut down the underlying S3 client.
176
- // The default behavior for shutdownNow shut's down the underlying s3 client
177
- // which will cause any following s3 operations to fail.
178
- tx .shutdownNow (false );
179
-
180
- // copy to [name]-latest.zip
181
- String copyKey = getLatestS3BundleKey ();
182
- CopyObjectRequest copyObjRequest = new CopyObjectRequest (
183
- otpServer .s3Bucket , key , otpServer .s3Bucket , copyKey );
184
- FeedStore .s3Client .copyObject (copyObjRequest );
185
- LOG .info ("Copied to s3://{}/{}" , otpServer .s3Bucket , copyKey );
186
- } catch (AmazonClientException |InterruptedException e ) {
187
- statusMessage = String .format ("Error uploading (or copying) deployment bundle to s3://%s/%s" , otpServer .s3Bucket , key );
188
- LOG .error (statusMessage );
189
- e .printStackTrace ();
168
+ uploadBundleToS3 ();
169
+ } catch (AmazonClientException | InterruptedException e ) {
170
+ statusMessage = String .format ("Error uploading (or copying) deployment bundle to s3://%s" , s3Bucket );
171
+ LOG .error (statusMessage , e );
190
172
status .fail (statusMessage );
191
- return ;
192
173
}
193
- LOG .info ("Uploaded to s3://{}/{}" , otpServer .s3Bucket , getS3BundleKey ());
194
- status .update ("Upload to S3 complete." , status .percentComplete + 10 );
195
- status .uploadingS3 = false ;
174
+
196
175
}
197
176
177
+ // Handle spinning up new EC2 servers for the load balancer's target group.
198
178
if (otpServer .targetGroupArn != null ) {
199
179
if ("true" .equals (DataManager .getConfigPropertyAsText ("modules.deployment.ec2.enabled" ))) {
200
- createServer ();
180
+ replaceEC2Servers ();
201
181
// If creating a new server, there is no need to deploy to an existing one.
202
182
return ;
203
183
} else {
@@ -209,11 +189,46 @@ public void jobLogic () {
209
189
}
210
190
211
191
// If there are no OTP targets (i.e. we're only deploying to S3), we're done.
212
- if (otpServer .internalUrl == null ) {
213
- status .completed = true ;
214
- return ;
192
+ if (otpServer .internalUrl != null ) {
193
+ // If we come to this point, there are internal URLs we need to deploy to (i.e., build graph over the wire).
194
+ boolean sendOverWireSuccessful = buildGraphOverWire ();
195
+ if (!sendOverWireSuccessful ) return ;
196
+ // Set baseUrl after success.
197
+ status .baseUrl = otpServer .publicUrl ;
215
198
}
199
+ status .completed = true ;
200
+ }
216
201
202
+ private void uploadBundleToS3 () throws InterruptedException , AmazonClientException {
203
+ status .message = "Uploading to S3" ;
204
+ status .uploadingS3 = true ;
205
+ String key = getS3BundleKey ();
206
+ LOG .info ("Uploading deployment {} to s3://{}/{}" , deployment .name , s3Bucket , key );
207
+ TransferManager tx = TransferManagerBuilder .standard ().withS3Client (FeedStore .s3Client ).build ();
208
+ final Upload upload = tx .upload (s3Bucket , key , deploymentTempFile );
209
+
210
+ upload .addProgressListener (
211
+ (ProgressListener ) progressEvent -> status .percentUploaded = upload .getProgress ().getPercentTransferred ()
212
+ );
213
+
214
+ upload .waitForCompletion ();
215
+
216
+ // Shutdown the Transfer Manager, but don't shut down the underlying S3 client.
217
+ // The default behavior for shutdownNow shut's down the underlying s3 client
218
+ // which will cause any following s3 operations to fail.
219
+ tx .shutdownNow (false );
220
+
221
+ // copy to [name]-latest.zip
222
+ String copyKey = getLatestS3BundleKey ();
223
+ CopyObjectRequest copyObjRequest = new CopyObjectRequest (s3Bucket , key , s3Bucket , copyKey );
224
+ FeedStore .s3Client .copyObject (copyObjRequest );
225
+ LOG .info ("Copied to s3://{}/{}" , s3Bucket , copyKey );
226
+ LOG .info ("Uploaded to s3://{}/{}" , s3Bucket , getS3BundleKey ());
227
+ status .update ("Upload to S3 complete." , status .percentComplete + 10 );
228
+ status .uploadingS3 = false ;
229
+ }
230
+
231
+ private boolean buildGraphOverWire () {
217
232
// figure out what router we're using
218
233
String router = deployment .routerId != null ? deployment .routerId : "default" ;
219
234
@@ -267,7 +282,7 @@ public void jobLogic () {
267
282
LOG .error (statusMessage );
268
283
e .printStackTrace ();
269
284
status .fail (statusMessage );
270
- return ;
285
+ return false ;
271
286
}
272
287
273
288
// retrieveById the input file
@@ -277,7 +292,7 @@ public void jobLogic () {
277
292
} catch (FileNotFoundException e ) {
278
293
LOG .error ("Internal error: could not read dumped deployment!" );
279
294
status .fail ("Internal error: could not read dumped deployment!" );
280
- return ;
295
+ return false ;
281
296
}
282
297
283
298
try {
@@ -286,7 +301,7 @@ public void jobLogic () {
286
301
statusMessage = String .format ("Unable to open connection to OTP server %s" , url );
287
302
LOG .error (statusMessage );
288
303
status .fail (statusMessage );
289
- return ;
304
+ return false ;
290
305
}
291
306
292
307
// copy
@@ -297,7 +312,7 @@ public void jobLogic () {
297
312
LOG .error (statusMessage );
298
313
e .printStackTrace ();
299
314
status .fail (statusMessage );
300
- return ;
315
+ return false ;
301
316
}
302
317
303
318
try {
@@ -307,7 +322,7 @@ public void jobLogic () {
307
322
LOG .error (message );
308
323
e .printStackTrace ();
309
324
status .fail (message );
310
- return ;
325
+ return false ;
311
326
}
312
327
313
328
try {
@@ -326,8 +341,8 @@ public void jobLogic () {
326
341
if (code != HttpURLConnection .HTTP_CREATED ) {
327
342
// Get input/error stream from connection response.
328
343
InputStream stream = code < HttpURLConnection .HTTP_BAD_REQUEST
329
- ? conn .getInputStream ()
330
- : conn .getErrorStream ();
344
+ ? conn .getInputStream ()
345
+ : conn .getErrorStream ();
331
346
String response ;
332
347
try (Scanner scanner = new Scanner (stream )) {
333
348
scanner .useDelimiter ("\\ Z" );
@@ -338,7 +353,7 @@ public void jobLogic () {
338
353
status .fail (statusMessage );
339
354
// Skip deploying to any other servers.
340
355
// There is no reason to take out the rest of the servers, it's going to have the same result.
341
- return ;
356
+ return false ;
342
357
}
343
358
} catch (IOException e ) {
344
359
statusMessage = String .format ("Could not finish request to server %s" , url );
@@ -350,9 +365,7 @@ public void jobLogic () {
350
365
tasksCompleted ++;
351
366
status .percentComplete = 100.0 * (double ) tasksCompleted / totalTasks ;
352
367
}
353
-
354
- status .completed = true ;
355
- status .baseUrl = otpServer .publicUrl ;
368
+ return true ;
356
369
}
357
370
358
371
private String getS3BundleKey () {
@@ -388,7 +401,7 @@ public void jobFinished () {
388
401
NotifyUsersForSubscriptionJob .createNotification ("deployment-updated" , deployment .id , message );
389
402
}
390
403
391
- public void createServer () {
404
+ public void replaceEC2Servers () {
392
405
try {
393
406
// First start graph-building instance and wait for graph to successfully build.
394
407
List <Instance > instances = startEC2Instances (1 );
@@ -460,7 +473,7 @@ private List<Instance> startEC2Instances(int count) {
460
473
// 2. Time to live until shutdown/termination (for test servers)
461
474
// 3. Hosting / nginx
462
475
// FIXME: Allow for r5 servers to be created.
463
- String userData = constructUserData (otpServer . s3Bucket , deployment .r5 );
476
+ String userData = constructUserData (deployment .r5 );
464
477
// The subnet ID should only change if starting up a server in some other AWS account. This is not
465
478
// likely to be a requirement.
466
479
// Define network interface so that a public IP can be associated with server.
@@ -538,7 +551,7 @@ private List<String> getIds (List<Instance> instances) {
538
551
return instances .stream ().map (Instance ::getInstanceId ).collect (Collectors .toList ());
539
552
}
540
553
541
- private String constructUserData (String s3Bucket , boolean r5 ) {
554
+ private String constructUserData (boolean r5 ) {
542
555
// Prefix/name of JAR file (WITHOUT .jar) FIXME: make this configurable.
543
556
String jarName = r5 ? deployment .r5Version : deployment .otpVersion ;
544
557
if (jarName == null ) {
@@ -563,12 +576,6 @@ private String constructUserData(String s3Bucket, boolean r5) {
563
576
lines .add (String .format ("LOGFILE=/var/log/%s.log" , tripPlanner ));
564
577
// Log user data setup to /var/log/user-data.log
565
578
lines .add ("exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1" );
566
- // Install the necessary files to run the trip planner. FIXME Remove. This should be captured by the AMI.
567
- // lines.add("apt update -y");
568
- // lines.add("apt install -y openjdk-8-jre");
569
- // lines.add("apt install -y openjfx");
570
- // lines.add("apt install -y awscli");
571
- // lines.add("apt install -y unzip");
572
579
// Create the directory for the graph inputs.
573
580
lines .add (String .format ("mkdir -p %s" , routerDir ));
574
581
lines .add (String .format ("chown ubuntu %s" , routerDir ));
0 commit comments