1616
1717package org .labkey .cluster ;
1818
19+ import org .apache .commons .io .FilenameUtils ;
1920import org .apache .commons .lang3 .StringUtils ;
2021import org .apache .logging .log4j .LogManager ;
2122import org .apache .logging .log4j .Logger ;
2223import org .labkey .api .action .ConfirmAction ;
24+ import org .labkey .api .action .SimpleRedirectAction ;
2325import org .labkey .api .action .SpringActionController ;
2426import org .labkey .api .data .DbSchema ;
2527import org .labkey .api .data .DbSchemaType ;
2628import org .labkey .api .data .Table ;
2729import org .labkey .api .data .TableInfo ;
30+ import org .labkey .api .pipeline .PipeRoot ;
2831import org .labkey .api .pipeline .PipelineJob ;
29- import org .labkey .api .pipeline .PipelineJobException ;
3032import org .labkey .api .pipeline .PipelineJobService ;
3133import org .labkey .api .pipeline .PipelineService ;
3234import org .labkey .api .pipeline .PipelineStatusFile ;
3537import org .labkey .api .security .RequiresPermission ;
3638import org .labkey .api .security .RequiresSiteAdmin ;
3739import org .labkey .api .security .permissions .AdminPermission ;
40+ import org .labkey .api .security .permissions .ReadPermission ;
41+ import org .labkey .api .settings .ResourceURL ;
3842import org .labkey .api .util .HtmlString ;
3943import org .labkey .api .util .PageFlowUtil ;
4044import org .labkey .api .util .URLHelper ;
45+ import org .labkey .api .view .ActionURL ;
4146import org .labkey .api .view .HtmlView ;
4247import org .labkey .cluster .pipeline .AbstractClusterExecutionEngine ;
4348import org .springframework .validation .BindException ;
4449import org .springframework .validation .Errors ;
4550import org .springframework .web .servlet .ModelAndView ;
4651
4752import java .io .File ;
48- import java .io .IOException ;
4953import java .util .ArrayList ;
5054import java .util .HashMap ;
5155import java .util .List ;
@@ -110,9 +114,10 @@ public URLHelper getSuccessURL(JobIdsForm form)
110114
111115 public ModelAndView getConfirmView (JobIdsForm form , BindException errors ) throws Exception
112116 {
117+
113118 return new HtmlView (HtmlString .unsafe ("This will change the status of the pipeline job with the provided ID to Cancelled. It is intended to help the situation when the normal UI leave a job in a perpetual 'Cancelling' state." +
114119 "To continue, enter a comma-delimited list of Job IDs and hit submit:<br><br>" +
115- "<label>Enter Job ID(s): </label><input name=\" jobIds\" ><br>" ));
120+ "<label>Enter Job ID(s): </label><input name=\" jobIds\" value = \" " + form . getJobIds () + " \" ><br>" ));
116121 }
117122
118123 public boolean handlePost (JobIdsForm form , BindException errors ) throws Exception
@@ -274,7 +279,7 @@ public ModelAndView getConfirmView(JobIdsForm form, BindException errors) throws
274279 {
275280 return new HtmlView (HtmlString .unsafe ("This will attempt to re-queue existing pipeline jobs using their serialized JSON text files. It is intended as a workaround for the situation where a job has been marked complete." +
276281 "To continue, enter a comma-delimited list of Job IDs and hit submit:<br><br>" +
277- "<label>Enter Job ID(s): </label><input name=\" jobIds\" ><br>" ));
282+ "<label>Enter Job ID(s): </label><input name=\" jobIds\" value= \" " + form . getJobIds () + " \" ><br>" ));
278283 }
279284
280285 public boolean handlePost (JobIdsForm form , BindException errors ) throws Exception
@@ -306,28 +311,133 @@ public boolean handlePost(JobIdsForm form, BindException errors) throws Exceptio
306311 sfs .add (sf );
307312 }
308313
309- sfs .forEach (sf -> {
314+ for (PipelineStatusFile sf : sfs )
315+ {
310316 File log = new File (sf .getFilePath ());
311317 File json = AbstractClusterExecutionEngine .getSerializedJobFile (log );
312318 if (!json .exists ())
313319 {
314- return ;
320+ errors .reject (ERROR_MSG , "Unable to find pipeline JSON, expected: " + json .getPath ());
321+ return false ;
315322 }
316323
324+ PipelineJob job = null ;
317325 try
318326 {
319- PipelineJob job = PipelineJob .readFromFile (json );
327+ job = PipelineJob .readFromFile (json );
320328
321- _log . info ("Submitting job: " + job .getJobGUID () + ": " + job .getActiveTaskStatus ());
329+ job . getLogger (). info ("Submitting job from JSON : " + job .getJobGUID () + ": " + job .getActiveTaskStatus ());
322330 PipelineService .get ().setPipelineJobStatus (job , job .getActiveTaskStatus ());
323331 }
324- catch (PipelineJobException | IOException e )
332+ catch (Exception e )
325333 {
326- _log .error (e );
334+ if (job != null )
335+ {
336+ job .getLogger ().error ("Unable to requeue job" , e );
337+ }
338+ else
339+ {
340+ _log .error ("Unable to requeue pipeline job" , e );
341+ }
342+
343+ errors .reject (ERROR_MSG , "Unable to requeue pipeline job: " + e .getMessage ());
344+ return false ;
327345 }
328- });
346+ }
329347
330348 return true ;
331349 }
332350 }
351+
352+ @ RequiresPermission (ReadPermission .class )
353+ public static class ViewJavaLogAction extends SimpleRedirectAction <ViewJavaLogForm >
354+ {
355+ @ Override
356+ public void validate (ViewJavaLogForm viewJavaLogForm , BindException errors )
357+ {
358+ super .validate (viewJavaLogForm , errors );
359+
360+ if (viewJavaLogForm .getJobId () == null )
361+ {
362+ errors .reject (ERROR_MSG , "Must provide JobId" );
363+ }
364+
365+ PipelineStatusFile sf = PipelineService .get ().getStatusFile (viewJavaLogForm .getJobId ());
366+ if (sf == null )
367+ {
368+ errors .reject (ERROR_MSG , "Unknown job: " + viewJavaLogForm .getJobId ());
369+ }
370+ else if (!sf .lookupContainer ().hasPermission (getUser (), ReadPermission .class ))
371+ {
372+ errors .reject (ERROR_MSG , "The current user does not have permission to view the folder: " + sf .lookupContainer ().getPath ());
373+ }
374+ }
375+
376+ @ Override
377+ public URLHelper getRedirectURL (ViewJavaLogForm viewJavaLogForm ) throws Exception
378+ {
379+ PipelineStatusFile sf = PipelineService .get ().getStatusFile (viewJavaLogForm .getJobId ());
380+ File parentDir = new File (sf .getFilePath ()).getParentFile ();
381+ if (!parentDir .exists ())
382+ {
383+ throw new IllegalArgumentException ("Log directory doesnt exist: " + parentDir .getPath ());
384+ }
385+
386+ File [] javaLogs = parentDir .listFiles ((dir , name ) -> {
387+ return name .endsWith (".java.log" );
388+ });
389+
390+ if (javaLogs == null || javaLogs .length == 0 )
391+ {
392+ throw new IllegalArgumentException ("No files ending with java.log found: " + parentDir .getPath ());
393+ }
394+
395+ long lastModifiedTime = Long .MIN_VALUE ;
396+ File chosenFile = null ;
397+ for (File file : javaLogs )
398+ {
399+ if (file .lastModified () > lastModifiedTime )
400+ {
401+ chosenFile = file ;
402+ lastModifiedTime = file .lastModified ();
403+ }
404+ }
405+
406+ PipeRoot root = PipelineService .get ().getPipelineRootSetting (sf .lookupContainer ());
407+ if (root == null )
408+ {
409+ throw new IllegalArgumentException ("Unable to find pipeline root for folder: " + sf .lookupContainer ().getPath ());
410+ }
411+
412+ if (!root .isUnderRoot (chosenFile ))
413+ {
414+ throw new IllegalArgumentException ("Log file is not under the pipeline root for folder: " + sf .lookupContainer ().getPath ());
415+ }
416+
417+ String relPath = root .relativePath (chosenFile );
418+ if (relPath == null )
419+ {
420+ throw new IllegalArgumentException ("Unable to find log file path for folder: " + sf .lookupContainer ().getPath ());
421+ }
422+
423+ relPath = org .labkey .api .util .Path .parse (FilenameUtils .separatorsToUnix (relPath )).encode ();
424+
425+ return new URLHelper (root .getWebdavURL () + relPath );
426+ }
427+ }
428+
429+ public static class ViewJavaLogForm
430+ {
431+ private Integer _jobId ;
432+
433+ public Integer getJobId ()
434+ {
435+ return _jobId ;
436+ }
437+
438+ public void setJobId (Integer jobId )
439+ {
440+ _jobId = jobId ;
441+ }
442+ }
333443}
0 commit comments