001    /*
002     * ZipSandbox.java
003     *
004     * Created on October 26, 2005, 12:54 PM
005     *
006     * This file is part of the STAR Scheduler.
007     * Copyright (c) 2003-2006 STAR Collaboration - Brookhaven National Laboratory
008     *
009     * STAR Scheduler is free software; you can redistribute it and/or modify
010     * it under the terms of the GNU General Public License as published by
011     * the Free Software Foundation; either version 2 of the License, or
012     * (at your option) any later version.
013     *
014     * STAR Scheduler is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017     * GNU General Public License for more details.
018     *
019     * You should have received a copy of the GNU General Public License
020     * along with STAR Scheduler; if not, write to the Free Software
021     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
022     */
023    
024    package gov.bnl.star.offline.scheduler.util.sandbox;
025    import gov.bnl.star.offline.scheduler.util.sandbox.Sandbox;
026    import gov.bnl.star.offline.scheduler.util.CSHCommandLineTask;
027    import gov.bnl.star.offline.scheduler.util.FilesystemToolkit;
028    import gov.bnl.star.offline.scheduler.util.ConfigToolkit;
029    
030    import gov.bnl.star.offline.scheduler.request.Request;
031    
032    import gov.bnl.star.offline.scheduler.Job;
033    import java.net.MalformedURLException;
034    
035    
036    import java.net.URL;
037    import java.util.List;
038    import java.util.ArrayList;
039    
040    import java.util.logging.Level;
041    import org.apache.log4j.Logger;
042    
043    
044    /**
045     * This sandbox variant will zip all files packaged by the user in the user's home directory. Then it will copy the zip to the users working directory and expand it.
046     * @author  Levente Hajdu
047     */
048    public class ZipSandbox implements Sandbox{ 
049        static private Logger log = Logger.getLogger(ZipSandbox.class.getName());
050        
051        
052        
053        /** Creates a new instance of ZipSandbox */
054        public ZipSandbox() {}
055        
056        public String CopyCommand(SandboxPackage packageObj) { return ""; }
057        
058        /**Zip the users requested files
059         * @param packageObj The package object holding inforamtion about the files to be packaged.  
060         * @param request The request object of the job.
061         * @return True if the package was biult, else return false. 
062         **/
063        public boolean MakePackage(SandboxPackage packageObj, Request request) {
064            
065            int packageNumber = -1;
066            String dirName;
067            String buffer ="";
068            
069            //Todo: if the package is not local the rep-path also has to be check for the package, think of addeding it to the file name  
070            try{
071                
072               
073                
074                packageObj.setPackageName(packageObj.getPackageName().trim()); //trim the package name
075                
076                if(packageObj.getPackageName() != null){
077                    if(FilesystemToolkit.checkIfFileExists( new URL("file:" + packageObj.getPackageName()) ,true)){
078                        this.addSandboxedFiles((new URL(packageObj.getPackageName()).getFile()));
079                        packageAlreadyExistWarning(packageObj.getPackageName());
080                        return true;
081                    }
082                    else if(FilesystemToolkit.checkIfFileExists( new URL("file:" + packageObj.getPackageName() + ".zip" ) ,true)){
083                        packageObj.setPackageName(packageObj.getPackageName() + ".zip");
084                        this.addSandboxedFiles(packageObj.getPackageName());
085                        packageAlreadyExistWarning(packageObj.getPackageName());
086                        return true;
087                    }
088                    //The same as above but with uppercase ".ZIP"
089                    else if(FilesystemToolkit.checkIfFileExists( new URL("file:" + packageObj.getPackageName() + ".ZIP" ) ,true)){
090                        packageObj.setPackageName(packageObj.getPackageName() + ".ZIP");
091                        this.addSandboxedFiles(packageObj.getPackageName());
092                        packageAlreadyExistWarning(packageObj.getPackageName());
093                        return true;
094                    }
095                }
096                        
097            } catch (Exception e) {
098                
099                
100                buffer = "Could not find per-packed sandbox. This is normal if this is the first job being dispatched and you are having SUMS crate the pack the package for you.";
101                System.out.println(buffer);
102                log.error(buffer, e);
103            }
104            
105            System.out.println("\nPacking Sandbox");   
106            
107    
108            //If the package is not there and there is no files to biuld the package from, just give an error and exit
109            boolean packageNotValid = false;
110            if(packageObj.getFiles() == null) packageNotValid = true;
111            else if(packageObj.getFiles().size() == 0) packageNotValid = true;
112            if(packageNotValid){
113                System.out.println("\nZipsandbox could not find or make one of your packages because it contains zero files and does not already exist. \n\n");
114                System.exit(1);
115            }
116            
117            //give the package dir a name if it dose not have not
118            if(packageObj.getPackageName() == null){
119                do{
120                        packageNumber ++;
121                        dirName = "sched" + request.getID() + "_" + packageNumber + ".package";
122                        packageObj.setPackageName("sched" + request.getID() + "_" + packageNumber + ".package");
123                }while(FilesystemToolkit.checkIfDirExists( "./" + dirName , null, true));
124            }
125            
126            
127            //chech that the name is not already being used
128            else{ 
129               dirName = packageObj.getPackageName() + ".package";
130               if(FilesystemToolkit.checkIfDirExists( "./" + dirName , null, true)){
131                   System.out.println("Folder " + "./" + dirName + " already exists.");
132                   do{ //same loop as before 
133                        packageNumber ++;
134                        dirName = "sched" + request.getID() + "_" + packageNumber + ".package";
135                   }while(FilesystemToolkit.checkIfDirExists( "./" + dirName , null, true)); 
136                   System.out.println("Renaming to " + dirName);
137               }
138            }
139            
140            //Make the dir for the package
141            CSHCommandLineTask cwd = new CSHCommandLineTask("mkdir " + dirName, true);
142            System.out.print("makeing dir " + dirName);
143            cwd.run();
144            System.out.print("...done");
145            if(cwd.getExitStatus() != 0){
146                throw new RuntimeException("Error in creating directory \n\n" +
147                    "mkdir " + dirName + "\n" +
148                     cwd.getOutput() + "\n\n" +
149                    "gov.bnl.star.offline.scheduler.util.sandbox.ZipSandbox.MakePackage(SandboxPackage packageObj, Request request)");   
150            }
151            
152            
153            //copy all the file to the packing dir.
154            List files = new ArrayList(); 
155            for(int i = 0; i != packageObj.getFiles().size(); i++ ) files.add( packageObj.getFiles().get(i)); //copy all items from the packages file list the files array
156            for(int i = 0; i != packageObj.getDirectorys().size(); i++ ) files.add( packageObj.getDirectorys().get(i)); //copy all items from the packages directory list the files array
157            
158            for(int i = 0; i != files.size(); i ++){
159                URL file = (URL) files.get(i);   
160                
161                if(! FilesystemToolkit.checkIfFileExists(file ,true) ){
162                    System.out.println("\n\nWarning: The existence of the file or directory \" " + file.getFile() + "\" could not be validated. Please check that that the element exists. ");
163                }
164                
165               // if( file.getFile().matches("^\\./.*/.*/.*$")){
166                if( file.getFile().matches("^\\./.*/.*$")){  //if the path relative 
167     
168                    
169                    String relativePath = file.getFile().replaceAll("(^\\.)(/)(.*)(/.*$)", "$2$3");
170                    //inInstallCommand = inInstallCommand + "/bin/mkdir -p " + installDir + relativePath + "\n";
171                    
172                    buffer = "/bin/mkdir -p " + dirName + relativePath;
173                    log.info("Executing ---> " + buffer);
174                    cwd = new CSHCommandLineTask(buffer, true);
175                    System.out.print("Executing-->" + buffer);
176                    cwd.run();
177                    System.out.println("...done");
178                    if(cwd.getExitStatus() != 0) log.info("Command had a non-zero exit status \n" + buffer + "\n Command output \n" + cwd.getOutput());
179                    
180                    String source = file.getFile();
181                    source = source.endsWith("/") ? source + "*" : source; //remove the last slash if it has one 
182                    buffer = "/bin/cp -r -p " + source +" "+ dirName + relativePath;
183                    
184                    //buffer = "/bin/cp -r -p " + file.getFile() +" "+ dirName + relativePath;
185                    cwd = new CSHCommandLineTask(buffer, true);
186                    log.info("Executing ---> " + buffer);
187                    System.out.print("Executing ---> " + buffer);
188                    cwd.run();
189                    System.out.println("...done");
190                    if(cwd.getExitStatus() != 0)
191                        log.info("Command had a non-zero exit status \n" + buffer + "\n Command output \n" + cwd.getOutput());
192                    //inInstallCommand = inInstallCommand + lncommand + " -s " + file.getFile() + " " + installDir + relativePath + "/\n";
193                }else{
194                    
195                    //inInstallCommand = inInstallCommand + lncommand + " -s " + file.getFile() + " " + installDir + "\n"; 
196                    
197                    buffer = "/bin/cp -r -p " + file.getFile() +" "+ dirName + "/";
198                    cwd = new CSHCommandLineTask(buffer , true);
199                    log.info("Executing ---> " + buffer);
200                    System.out.print("Executing ---> " + buffer);
201                    cwd.run();
202                    System.out.println("...done");
203                    if(cwd.getExitStatus() != 0)
204                        log.info("Command had a non-zero exit status \n" + buffer + "\n Command output \n" + cwd.getOutput());   
205                }
206            }       
207            
208            if(packageObj.getPackageName().matches("(?i).*\\.zip$")){ //don't add .zip on to the string if it is already there or else the name would be bla.zip.zip
209                //ZipUtility.Zipdir(dirName, packageObj.getPackageName()); 
210                
211                //cwd = new CSHCommandLineTask("/usr/bin/zip ../" + packageObj.getPackageName() + " " + dirName + "/*", true);
212                
213                
214                //buffer = "cd " + dirName + "; find | /usr/bin/zip ../" + packageObj.getPackageName() + ".zip -@";
215                buffer = "cd " + dirName + "; find | /usr/bin/zip -y -v ../" + packageObj.getPackageName() + ".zip -@"; //cause a freez on some links
216                
217                log.info("Executing ---> " + buffer);
218                cwd = new CSHCommandLineTask(buffer, true);
219                System.out.print("Executing ---> " + buffer);
220                cwd.run();
221                System.out.println("...done");
222                if(cwd.getExitStatus() != 0)
223                        log.info("Command had a non-zero exit status \n" + buffer + "\n Command output \n" + cwd.getOutput());
224                this.addSandboxedFiles(packageObj.getPackageName()); //add this as a file that should be moved with the job
225            }
226            else{
227                //ZipUtility.Zipdir(dirName, packageObj.getPackageName() + ".zip" );
228                //cwd = new CSHCommandLineTask("/usr/bin/zip ../" + packageObj.getPackageName() + ".zip "  + dirName + "/*", true);
229                
230                
231                //buffer = "cd " + dirName + "; find | /usr/bin/zip ../" + packageObj.getPackageName() + ".zip -@";  //cause a freez on some links
232                buffer = "cd " + dirName + "; find | /usr/bin/zip -y -v ../" + packageObj.getPackageName() + ".zip -@";
233                
234                log.info("Executing ---> " + buffer);
235                //System.out.println("cd " + dirName + "; find | /usr/bin/zip ../" + packageObj.getPackageName() + ".zip -@");
236                cwd = new CSHCommandLineTask(buffer , true);
237                System.out.print("Executing ---> " + buffer);
238                cwd.run();
239                System.out.println("...done");
240                if(cwd.getExitStatus() != 0)
241                    log.info("Command had a non-zero exit status \n" + buffer + "\n Command output \n" + cwd.getOutput());
242                packageObj.setPackageName(packageObj.getPackageName() + ".zip");
243                this.addSandboxedFiles(packageObj.getPackageName()); //add this as a file that should be moved with the job
244            }
245            
246            System.out.println("\nZip Sandbox package "+ packageObj.getPackageName() +" created");   
247    
248            return true;
249        }
250        
251        public void packageAlreadyExistWarning(String fileName){
252            System.out.println("\n\nWarning : The zip Sandbox package " + fileName + " already exist in this directory, it will not be recreated. If you have made changes to the files you are sandboxing please delete " + fileName + " and resubmit the request else the existing package will be used.\n");
253            return;
254        }
255        
256        public boolean PackageExists(SandboxPackage packageObj) {
257            
258            
259                String packageURL = "file:" + packageObj.getRepository() + packageObj.getPackageName();
260    
261                try{    
262                    if (FilesystemToolkit.checkIfFileExists(new URL(packageURL), true )){ return true; }
263                 } catch (Exception e) {
264                    System.out.println("Could not check if \""+ packageURL +"\" exists as there was a malformed URL exception.");
265                    return false;
266                 }
267                
268            return false;
269        }
270        
271        public void Sandbox() {
272        }
273        
274        
275        
276        String findInstallDir(SandboxPackage packageObj){
277            String installDir;
278            if(packageObj.getInstalldir() == null){  //if nothing is stated use $SCRATCH
279                installDir = "$SCRATCH";
280            }
281            else if(packageObj.getInstalldir().compareTo("\\$.*") == 0){ // if the path is an inv. ver. just leave it 
282                installDir = packageObj.getInstalldir();
283            }
284            else if(packageObj.getInstalldir().startsWith(System.getProperty("file.separator"))){ //if the path is absolute, just leave it  
285                installDir = packageObj.getInstalldir();
286            }
287            else{
288                installDir = "$SCRATCH" + System.getProperty("file.separator") + packageObj.getInstalldir(); //if the path is relative, then it is relative to $SCRATCH  
289            } 
290            return installDir;
291        }
292        
293        
294        /**Chech program locations for unzip */
295    //    public String findUnzipcommand(Job job){
296    //        String unzipcommand = "/usr/bin/unzip";
297    //        boolean foundProgram = false;
298    //        if (job.getQueueObj().getBatchSystem().getSite().getProgramLocations() != null){
299    //            
300    //            if (job.getQueueObj().getBatchSystem().getSite().getProgramLocations().containsKey("unzip")){
301    //                unzipcommand = (String) job.getQueueObj().getBatchSystem().getSite().getProgramLocations().get("unzip");
302    //                foundProgram = true;
303    //            }            
304    //        }
305    //        if(! foundProgram){
306    //            System.out.println("\n\nWarning the program locations table could not find a record for program \"unzip\" at site " + job.getQueueObj().getBatchSystem().getSite().getSiteName());
307    //        }
308    //        return unzipcommand;
309    //    }
310        
311        
312        public String installCommand(SandboxPackage packageObj, Job job) {
313            
314            if(ConfigToolkit.getToolkit().isLocalQueue(job.getQueueObj()))
315                return localInstallCommand(packageObj, job);
316            else
317                return gridInstallCommand(packageObj, job);
318                
319        }
320        
321        
322        public String localInstallCommand(SandboxPackage packageObj, Job job) {
323    
324            String installDir = findInstallDir(packageObj);
325            String unzipcommand = ConfigToolkit.findProgram("unzip", job);
326    
327            //If the path to the unzip command is not found inside the sites program location table, we just have to hope the command is in the jobs path
328            return unzipcommand + " " +  packageObj.getPackageName()  + " -d " + installDir + "\n" ;
329        }
330        
331       
332        public String gridInstallCommand(SandboxPackage packageObj, Job job) {
333            
334    //        return "\nif (! -d $DATA) then" +"\n"+
335    //        "    echo 'Scheduler could not find $DATA\\n$DATA = '$DATA" +"\n"+
336    //        "    exit $STS" +"\n"+
337    //        "endif" +
338    //        "\n\n"+
339    //        "setenv PACKAGE " + packageObj.getPackageName() +"\n"+
340    //        "if (! -e $DATA/$REQUESTID/$PACKAGE) then"  +"\n"+
341    //        "        /bin/mkdir $DATA/$REQUESTID"  +"\n"+
342    //        "        /bin/cp $PACKAGE $DATA/$REQUESTID/$PACKAGE.$JOBID"  +"\n"+
343    //        "        /bin/mv $DATA/$REQUESTID/$PACKAGE.$JOBID $DATA/$REQUESTID/$PACKAGE"  +"\n"+
344    //        "endif"  +"\n"+
345    //        "/bin/rm $PACKAGE"  +"\n"+
346    //        findUnzipcommand(job) + " -n $DATA/$REQUESTID/$PACKAGE -d $DATA/$REQUESTID/"  +"\n"+
347    //        "/bin/ln -s $DATA/$REQUESTID/* "+ findInstallDir(packageObj) + "/"  +"\n";
348            
349            //check that $APP is setup 
350            
351            
352            
353    
354            return "\n"+
355            "if(! -d $DATA) then" +"\n"+
356            "         echo 'Sandbox fault: $DATA ('$DATA') does not exist or does not allow user write access. Possible causes may include SUMS miss-configuration or remote site file system fault.'" +"\n"+
357            "         exit"   +"\n"+
358            "endif"  +"\n"+
359            "setenv PACKAGE " + packageObj.getPackageName() +"\n"+
360            "if (! -e $DATA/STAR/$REQUESTID/$PACKAGE) then"  +"\n"+
361            "        if(! -d $DATA/STAR) then" +"\n"+
362            "            /bin/mkdir -p $DATA/STAR" +"\n"+
363            "            chmod 777 $DATA/STAR" + "\n"+
364            "        endif"  +"\n"+
365            "        /bin/mkdir -p $DATA/STAR/$REQUESTID"  +"\n"+
366            "        /bin/cp $PACKAGE $DATA/STAR/$REQUESTID/$PACKAGE.$JOBID"  +"\n"+
367            "        /bin/mv $DATA/STAR/$REQUESTID/$PACKAGE.$JOBID $DATA/STAR/$REQUESTID/$PACKAGE"  +"\n"+
368            "endif"  +"\n"+
369            "/bin/rm $PACKAGE"  +"\n"+
370            ConfigToolkit.findProgram("unzip", job) + " -n $DATA/STAR/$REQUESTID/$PACKAGE -d $DATA/STAR/$REQUESTID/"  +"\n"+
371            "/bin/ln -s $DATA/STAR/$REQUESTID/* "+ findInstallDir(packageObj) + "/"  +"\n";
372                
373        }
374        
375      
376        List packages = new ArrayList();
377        
378        public void setPackages(java.util.List packages) {
379            this.packages = packages;
380        }
381        
382        /** Returns a List of sandboxPackage object that are part of the sandbox */
383        public List getPackages(){
384            return packages;
385        }
386        
387        /** Used to add a package to the sand box */
388        public void addPackage(SandboxPackage sandboxPackage){
389               packages.add(sandboxPackage);
390        }
391        
392        
393        
394        List SandboxedFiles = new ArrayList();
395        /* Gets the files that the sand box has packed. */
396        public List getSandboxedFiles(){ return SandboxedFiles; }
397        /* Sets the files that the sand box has packed. */
398        public void setSandboxedFiles(List SandboxedFiles){ this.SandboxedFiles = SandboxedFiles; }
399        /* Adds a file to the list of sandboxed files. */
400        public void addSandboxedFiles(String file){ SandboxedFiles.add(file); }
401        
402        public String InitializationCommands() { return ""; }
403        
404    }