11package org .labkey .api .sequenceanalysis .run ;
22
3+ import org .apache .commons .io .FileUtils ;
34import org .apache .commons .lang3 .StringUtils ;
45import org .apache .logging .log4j .Logger ;
56import org .jetbrains .annotations .Nullable ;
67import org .labkey .api .pipeline .PipelineJobException ;
78import org .labkey .api .sequenceanalysis .pipeline .PipelineContext ;
89import org .labkey .api .sequenceanalysis .pipeline .PipelineOutputTracker ;
910import org .labkey .api .sequenceanalysis .pipeline .SequencePipelineService ;
11+ import org .labkey .api .util .FileUtil ;
1012import org .labkey .api .writer .PrintWriters ;
1113
1214import java .io .File ;
@@ -28,7 +30,8 @@ public class DockerWrapper extends AbstractCommandWrapper
2830 private final PipelineContext _ctx ;
2931 private File _tmpDir = null ;
3032 private String _entryPoint = null ;
31- private boolean _runPrune = true ;
33+ private boolean _runPrune = false ;
34+ private boolean _useLocalContainerStorage ;
3235 private String _alternateUserHome = null ;
3336 private final Map <String , String > _dockerEnvironment = new HashMap <>();
3437
@@ -37,6 +40,8 @@ public DockerWrapper(String containerName, Logger log, PipelineContext ctx)
3740 super (log );
3841 _containerName = containerName ;
3942 _ctx = ctx ;
43+
44+ _useLocalContainerStorage = SequencePipelineService .get ().useLocalDockerContainerStorage ();
4045 }
4146
4247 public void setAlternateUserHome (String alternateUserHome )
@@ -59,6 +64,11 @@ public void setRunPrune(boolean runPrune)
5964 _runPrune = runPrune ;
6065 }
6166
67+ public void setUseLocalContainerStorage (boolean useLocalContainerStorage )
68+ {
69+ _useLocalContainerStorage = useLocalContainerStorage ;
70+ }
71+
6272 public void executeWithDocker (List <String > containerArgs , File workDir , PipelineOutputTracker tracker ) throws PipelineJobException
6373 {
6474 executeWithDocker (containerArgs , workDir , tracker , null );
@@ -79,14 +89,34 @@ public void executeWithDocker(List<String> containerArgs, File workDir, Pipeline
7989 writer .println ("set -e" );
8090
8191 writer .println ("DOCKER='" + SequencePipelineService .get ().getDockerCommand () + "'" );
82- writer .println ("$DOCKER pull " + _containerName );
92+
93+ writer .println ("IMAGE_EXISTS=`$DOCKER images -q \" " + getEffectiveContainerName () + "\" | wc -l`" );
94+ writer .println ("LOCAL=not_present" );
95+ writer .println ("if [[ $IMAGE_EXISTS > 0 ]];then" );
96+ writer .println ("\t LOCAL=`docker inspect --format='{{.Digest}}' " + getEffectiveContainerName () + "`" );
97+ writer .println ("fi" );
98+ writer .println ("LATEST=`regctl image digest --list " + getEffectiveContainerName () + "`" );
99+ writer .println ("if [ $LOCAL != $LATEST ];then" );
100+ writer .println ("\t $DOCKER pull " + getLocalStorageArgs () + getEffectiveContainerName ());
101+ writer .println ("else" );
102+ writer .println ("\t echo 'Image up to date'" );
103+ writer .println ("fi" );
104+
83105 if (_runPrune )
84106 {
85- writer .println ("$DOCKER image prune -f" );
107+ writer .println ("$DOCKER image prune " + getLocalStorageArgs () + " -f" );
86108 }
87109
88110 writer .println ("$DOCKER run --rm=true \\ " );
89111 writer .println ("\t --group-add keep-groups \\ " );
112+ writer .println ("\t --transient-store \\ " );
113+
114+ if (_useLocalContainerStorage )
115+ {
116+ getLogger ().debug ("Using local container storage: " + getLocalContainerDir ().getPath ());
117+ prepareLocalStorage ();
118+ writer .println ("\t " + getLocalStorageArgs () + "\\ " );
119+ }
90120
91121 // NOTE: getDockerVolumes() should be refactored to remove the -v and this logic should be updated accordingly:
92122 File homeDir = new File (System .getProperty ("user.home" ));
@@ -149,7 +179,7 @@ public void executeWithDocker(List<String> containerArgs, File workDir, Pipeline
149179 {
150180 writer .println ("\t -e " + key + "='" + _dockerEnvironment .get (key ) + "' \\ " );
151181 }
152- writer .println ("\t " + _containerName + " \\ " );
182+ writer .println ("\t " + getEffectiveContainerName () + " \\ " );
153183 writer .println ("\t " + dockerBashScript .getPath ());
154184 writer .println ("DOCKER_EXIT_CODE=$?" );
155185 writer .println ("echo 'Docker run exit code: '$DOCKER_EXIT_CODE" );
@@ -170,6 +200,23 @@ public void executeWithDocker(List<String> containerArgs, File workDir, Pipeline
170200 localBashScript .setExecutable (true );
171201 dockerBashScript .setExecutable (true );
172202 execute (Arrays .asList ("/bin/bash" , localBashScript .getPath ()));
203+
204+ if (_useLocalContainerStorage )
205+ {
206+ try
207+ {
208+ FileUtils .deleteDirectory (getLocalContainerDir ());
209+ }
210+ catch (IOException e )
211+ {
212+ throw new PipelineJobException (e );
213+ }
214+ }
215+ }
216+
217+ private String getEffectiveContainerName ()
218+ {
219+ return _containerName ;
173220 }
174221
175222 public void addToDockerEnvironment (String key , String value )
@@ -203,4 +250,39 @@ private Collection<File> inspectInputFiles(Collection<File> inputFiles)
203250
204251 return Collections .emptySet ();
205252 }
253+
254+ private File getLocalContainerDir ()
255+ {
256+ return new File (SequencePipelineService .get ().getJavaTempDir (), "containers" );
257+ }
258+
259+ private File prepareLocalStorage () throws PipelineJobException
260+ {
261+ try
262+ {
263+ if (getLocalContainerDir ().exists ())
264+ {
265+ getLogger ().debug ("Deleting existing container dir: " + getLocalContainerDir ());
266+ FileUtils .deleteDirectory (getLocalContainerDir ());
267+ }
268+
269+ FileUtil .createDirectory (getLocalContainerDir ().toPath ());
270+
271+ return getLocalContainerDir ();
272+ }
273+ catch (IOException e )
274+ {
275+ throw new PipelineJobException (e );
276+ }
277+ }
278+
279+ private String getLocalStorageArgs ()
280+ {
281+ if (!_useLocalContainerStorage )
282+ {
283+ return "" ;
284+ }
285+
286+ return "--root=" + getLocalContainerDir ().getPath () + " " ;
287+ }
206288}
0 commit comments