/** * Copyright 2007-2008 University Of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.isi.pegasus.planner.refiner; import edu.isi.pegasus.common.logging.LogManager; import edu.isi.pegasus.common.util.DynamicLoader; import edu.isi.pegasus.common.util.FactoryException; import edu.isi.pegasus.common.util.PegasusURL; import edu.isi.pegasus.common.util.Separator; import edu.isi.pegasus.common.util.Version; import edu.isi.pegasus.planner.catalog.classes.SysInfo; import edu.isi.pegasus.planner.catalog.site.classes.FileServer; import edu.isi.pegasus.planner.catalog.site.classes.SiteCatalogEntry; import edu.isi.pegasus.planner.catalog.site.classes.SiteStore; import edu.isi.pegasus.planner.catalog.transformation.Mapper; import edu.isi.pegasus.planner.catalog.transformation.TransformationCatalogEntry; import edu.isi.pegasus.planner.catalog.transformation.classes.TCType; import edu.isi.pegasus.planner.classes.ADag; import edu.isi.pegasus.planner.classes.FileTransfer; import edu.isi.pegasus.planner.classes.Job; import edu.isi.pegasus.planner.classes.NameValue; import edu.isi.pegasus.planner.classes.PegasusBag; import edu.isi.pegasus.planner.classes.Profile; import edu.isi.pegasus.planner.classes.TransferJob; import edu.isi.pegasus.planner.code.gridstart.PegasusExitCode; import edu.isi.pegasus.planner.common.CreateWorkerPackage; import edu.isi.pegasus.planner.common.PegasusConfiguration; import edu.isi.pegasus.planner.mapper.SubmitMapper; import edu.isi.pegasus.planner.namespace.Dagman; import edu.isi.pegasus.planner.namespace.Pegasus; import edu.isi.pegasus.planner.partitioner.graph.GraphNode; import edu.isi.pegasus.planner.selector.TransformationSelector; import edu.isi.pegasus.planner.transfer.Implementation; import edu.isi.pegasus.planner.transfer.Refiner; import edu.isi.pegasus.planner.transfer.RemoteTransfer; import edu.isi.pegasus.planner.transfer.implementation.ImplementationFactory; import edu.isi.pegasus.planner.transfer.refiner.RefinerFactory; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * The refiner that is responsible for adding * - setup nodes that deploy a worker package on each deployment site at start * of workflow execution * - cleanup nodes that undeploy a worker package on each deployment site at end * workflow execution * * @author Karan Vahi * @author Gaurang Mehta * * @version $Revision: 538 $ */ public class DeployWorkerPackage extends Engine { /** * Constant suffix for the names of the deployment nodes. */ public static final String DEPLOY_WORKER_PREFIX = "stage_worker_"; /** * Constant suffix for the names of the deployment nodes. */ public static final String UNTAR_PREFIX = "untar_"; /** * Constant suffix for the names of the deployment nodes. */ public static final String CLEANUP_PREFIX = "cleanup_"; /** * The arguments for pegasus-exitcode when you only want the log files to be rotated. */ public static final String POSTSCRIPT_ARGUMENTS_FOR_ONLY_ROTATING_LOG_FILE = "-r $RETURN"; /** * Array storing the names of the executables in the $PEGASUS_HOME/bin directory * Associates the transformation name with the executable basenames */ public static final String PEGASUS_WORKER_EXECUTABLES[][] = { { "transfer", "pegasus-transfer" }, { "kickstart", "pegasus-kickstart" }, { "cleanup", "pegasus-transfer" }, { "seqexec", "pegasus-cluster"}, { "dirmanager", "pegasus-transfer" }, { "keg" , "pegasus-keg" }, }; /** * Store the regular expressions necessary to parse the basename from the worker * package url to retrieve the version of pegasus. * * pegasus-worker-4.6.0dev-x86_64_macos_10.tar.gz */ private static final String mRegexExpression = // "(pegasus-)(binary|worker)-([0-9]\\.[0-9]\\.[0-9][a-zA-Z]*)-x86.*"; "(pegasus-)(binary|worker)-([0-9]\\.[0-9]\\.[0-9][a-zA-Z0-9]*)-(x86|x86_64|ia64|ppc)_([a-zA-Z0-9]*)_([0-9]*).tar.gz"; /** * The path to be set for create dir jobs. */ public static final String PATH_VALUE = ".:/bin:/usr/bin:/usr/ucb/bin"; /** * The default transfer refiner name. */ public static final String DEFAULT_REFINER = "Basic"; /** * The transformation namespace for the worker package */ public static final String TRANSFORMATION_NAMESPACE = "pegasus"; /** * The logical name of the worker package */ public static final String TRANSFORMATION_NAME = "worker"; /** * The version number for the worker package. */ public static final String TRANSFORMATION_VERSION = null; /** * The transformation namespace for the worker package */ public static final String UNTAR_TRANSFORMATION_NAMESPACE = null; /** * The logical name of the worker package */ public static final String UNTAR_TRANSFORMATION_NAME = "tar"; /** * The version number for the worker package. */ public static final String UNTAR_TRANSFORMATION_VERSION = null; /** * The complete TC name for untar. */ public static final String COMPLETE_UNTAR_TRANSFORMATION_NAME = Separator.combine( UNTAR_TRANSFORMATION_NAMESPACE, UNTAR_TRANSFORMATION_NAME, UNTAR_TRANSFORMATION_VERSION ); /** * The complete TC name for pegasus worker package. */ public static final String COMPLETE_TRANSFORMATION_NAME = Separator.combine( TRANSFORMATION_NAMESPACE, TRANSFORMATION_NAME, TRANSFORMATION_VERSION ); /** * The derivation namespace for the worker package. */ public static final String DERIVATION_NAMESPACE = "pegasus"; /** * The logical name of the transformation for the worker package */ public static final String DERIVATION_NAME = "worker"; /** * The version number for the derivations for worker package. */ public static final String DERIVATION_VERSION = "2.0"; /** * The derivation namespace for the untar job. */ public static final String UNTAR_DERIVATION_NAMESPACE = null; /** * The logical name of the transformation for the untar job. */ public static final String UNTAR_DERIVATION_NAME = "worker"; /** * The version number for the derivations for untar job. */ public static final String UNTAR_DERIVATION_VERSION = "2.0"; /** * The name of the package in which all the implementing classes are. */ public static final String PACKAGE_NAME = "edu.isi.pegasus.planner.refiner."; /** * The base directory URL for the builds. */ public static final String BASE_BUILD_DIRECTORY_URL = "http://download.pegasus.isi.edu/pegasus/"; /** * The version of pegasus matching the planner. */ public static final String PEGASUS_VERSION = Version.instance().toString(); /** * The name of the refiner for purposes of error logging */ public static final String REFINER_NAME = "DeployWorkerPackage"; /** * Stores compiled patterns at first use, quasi-Singleton. */ private static Pattern mPattern = null; /** * The map storing OS to corresponding NMI OS platforms. */ private static Map<SysInfo.OS,String> mOSToNMIOSReleaseAndVersion = null; /** * A set of supported OS release and versions that our build process * builds for. */ private static Set<String> mSupportedOSReleaseVersions = null; /** * Maps each to OS to a specific OS release for purposes of picking up the * correct worker package for a site. The mapping is to be kept consistent * with the NMI builds for the releases. * * * @return map */ private static Map<SysInfo.OS,String> osToOSReleaseAndVersion(){ //singleton access if( mOSToNMIOSReleaseAndVersion == null ){ mOSToNMIOSReleaseAndVersion = new HashMap(); mOSToNMIOSReleaseAndVersion.put( SysInfo.OS.linux, "rhel_6" ); mOSToNMIOSReleaseAndVersion.put( SysInfo.OS.macosx, "macos_10" ); } return mOSToNMIOSReleaseAndVersion; } /** * A set of OS release and version combinations for which our build * processes build Pegasus binaries. * * @return */ private static Set<String> supportedOSReleaseAndVersions(){ if( mSupportedOSReleaseVersions == null ){ mSupportedOSReleaseVersions = new HashSet(); mSupportedOSReleaseVersions.add( "rhel_6" ); mSupportedOSReleaseVersions.add( "rhel_7" ); mSupportedOSReleaseVersions.add( "deb_7" ); mSupportedOSReleaseVersions.add( "deb_8" ); mSupportedOSReleaseVersions.add( "ubuntu_14" ); mSupportedOSReleaseVersions.add( "ubuntu_16" ); mSupportedOSReleaseVersions.add( "macos_10" ); } return mSupportedOSReleaseVersions; } /** * It is a reference to the Concrete Dag so far. */ protected ADag mCurrentDag; /** * The job prefix that needs to be applied to the job file basenames. */ protected String mJobPrefix; /** * The transfer implementation to be used for staging in the data as part * of setup job. */ protected Implementation mSetupTransferImplementation; /** * The FileTransfer map indexed by site id. */ protected Map<String, FileTransfer> mFTMap; /** * Map that indicates whether we need local setup transfer jobs for a site or * not. */ protected Map<String, Boolean> mLocalTransfers; /** * Maps a site to the the directory where the pegasus worker package has * been untarred during workflow execution. */ protected Map<String,String> mSiteToPegasusHomeMap; /** * The user specified location from where to stage the worker packages. */ protected String mUserSpecifiedSourceLocation; /** * Boolean indicating whether to use the user specified location or not */ protected boolean mUseUserSpecifiedSourceLocation; /** * Boolean indicating whether user wants the worker package to be transferred * or not. */ protected boolean mTransferWorkerPackage; /** * Boolean indicating worker node execution. */ //protected boolean mWorkerNodeExecution; /** * Loads the implementing class corresponding to the mode specified by the * user at runtime. * * @param bag bag of initialization objects * * @return instance of a DeployWorkerPackage implementation * * @throws FactoryException that nests any error that * might occur during the instantiation of the implementation. */ public static DeployWorkerPackage loadDeployWorkerPackage( PegasusBag bag ) throws FactoryException { //prepend the package name String className = PACKAGE_NAME + "DeployWorkerPackage"; //try loading the class dynamically DeployWorkerPackage dp = null; DynamicLoader dl = new DynamicLoader(className); try { Object argList[] = new Object[ 1 ]; argList[0] = bag; dp = (DeployWorkerPackage) dl.instantiate(argList); } catch (Exception e) { throw new FactoryException( "Instantiating Deploy Worker Package", className, e ); } return dp; } private Refiner mDefaultTransferRefiner; private File mSubmitHostWorkerPackage; /** * A pratically nothing constructor ! * * * @param bag bag of initialization objects */ public DeployWorkerPackage( PegasusBag bag ) { super( bag ); mCurrentDag = null; mFTMap = new HashMap(); mLocalTransfers = new HashMap(); mSiteToPegasusHomeMap = new HashMap<String,String>(); mJobPrefix = bag.getPlannerOptions().getJobnamePrefix(); mTransferWorkerPackage = mProps.transferWorkerPackage(); //mWorkerNodeExecution = mProps.executeOnWorkerNode(); //load the transfer setup implementation //To DO . specify type for loading /* PM-833 mSetupTransferImplementation = ImplementationFactory.loadInstance( bag, ImplementationFactory.TYPE_SETUP ); */ mUserSpecifiedSourceLocation = mProps.getBaseSourceURLForSetupTransfers(); mUseUserSpecifiedSourceLocation = !( mUserSpecifiedSourceLocation == null || mUserSpecifiedSourceLocation.trim().length()== 0 ); Version version = Version.instance(); } /** * Initialize with the scheduled graph. Results in the appropriate * population of the transformation catalog with pegasus-worker executables. * * * @param scheduledDAG the scheduled workflow. */ public void initialize( ADag scheduledDAG ) { Mapper m = mBag.getHandleToTransformationMapper(); if( !m.isStageableMapper() ){ //we want to load a stageable mapper mLogger.log( "User set mapper is not a stageable mapper. Loading a stageable mapper ", LogManager.DEBUG_MESSAGE_LEVEL ); m = Mapper.loadTCMapper( "Staged", mBag ); } RemoteTransfer remoteTransfers = new RemoteTransfer( mProps ); remoteTransfers.buildState(); Set[] deploymentSites = this.getDeploymentSites( scheduledDAG ); //figure if we need to deploy or not if( !mTransferWorkerPackage && ( deploymentSites[1].isEmpty() ) ){ //PM-810 user specified property is false for worker package //and nonsharedfs|condorio deployment is empty mLogger.log( "No Deployment of Worker Package needed" , LogManager.DEBUG_MESSAGE_LEVEL ); return; } mLogger.log( "Deployment of Worker Package needed", LogManager.DEBUG_MESSAGE_LEVEL ); //PM-888 we would need to deploy the worker package. //create one out of existing pegasus installation on the submit //host and set it up for use. CreateWorkerPackage cw = new CreateWorkerPackage( mBag ); //PM-1046 copy the worker package instead of creating our own mSubmitHostWorkerPackage = cw.copy( ); //load the transformation selector. different //selectors may end up being loaded for different jobs. TransformationSelector txSelector = TransformationSelector.loadTXSelector( mProps.getTXSelectorMode() ); mDefaultTransferRefiner = RefinerFactory.loadInstance( DeployWorkerPackage.DEFAULT_REFINER, mBag, scheduledDAG ) ; /* PM-833 mSetupTransferImplementation.setRefiner( mDefaultTransferRefiner ); */ if( mTransferWorkerPackage && !deploymentSites[0].isEmpty() ){ //PM-810 for sharedfs case, worker package transfer can only happen //if the property is set by the user in the proeprties file setupTCForWorkerPackageLocations( deploymentSites[0], m, txSelector, false ); } setupTCForWorkerPackageLocations( deploymentSites[1], m, txSelector, true ); } /** * Sets up the transformation catalog and populates it with executables * contained in the Pegasus worker package for the remote compute sites, * and the Pegasus worker package itself * * @param sites * @param mapper * @param selector * @param workerNodeExecution boolean indicating whether a job runs on sharedfs or local node filesytem */ protected void setupTCForWorkerPackageLocations( Set sites, Mapper mapper, TransformationSelector selector, boolean workerNodeExecution) { //a map indexed by execution site and the corresponding worker package //location in the submit directory Map<String,String> workerPackageMap = new HashMap<String,String>(); SiteStore siteStore = mBag.getHandleToSiteStore(); //for the pegasus lite case, we insert entries into the //transformation catalog for all worker package executables //the planner requires with just the basename boolean useFullPath = !( workerNodeExecution ); //for each site insert default entries for Pegasus //Worker Package in the Transformation Catalog for( Iterator it = sites.iterator(); it.hasNext(); ){ String site = ( String ) it.next(); TransformationCatalogEntry entry = this.getTCEntryForPegasusWorkerPackage(mapper, selector, site, workerNodeExecution); mLogger.log( "Worker Package Entry used for site " + site + " " + entry, LogManager.DEBUG_MESSAGE_LEVEL ); //register back into the transformation catalog //so that we do not need to worry about creating it again try{ mTCHandle.insert( entry , false ); } catch( Exception e ){ //just log as debug. as this is more of a performance improvement //than anything else mLogger.log( "Unable to register in the TC the default entry " + entry.getLogicalTransformation() + " for site " + site, e, LogManager.ERROR_MESSAGE_LEVEL ); //throw exception as throw new RuntimeException( e ); } } //for each scheduled site query TCMapper for( Iterator it = sites.iterator(); it.hasNext(); ){ String site = ( String ) it.next(); String stagingSite = workerNodeExecution ? "local":// For PegasusLite Jobs we stage to the submit directory site; //get the set of valid tc entries List entries = mapper.getTCList( DeployWorkerPackage.TRANSFORMATION_NAMESPACE, DeployWorkerPackage.TRANSFORMATION_NAME, DeployWorkerPackage.TRANSFORMATION_VERSION, site ); //get selected entries List selectedEntries = selector.getTCEntry( entries ); if( selectedEntries == null || selectedEntries.size() == 0 ){ throw new RuntimeException( "Unable to find a valid location to stage " + Separator.combine( DeployWorkerPackage.TRANSFORMATION_NAMESPACE, DeployWorkerPackage.TRANSFORMATION_NAME, DeployWorkerPackage.TRANSFORMATION_VERSION ) ); } //select the first entry from selector TransformationCatalogEntry selected = ( TransformationCatalogEntry )selectedEntries.get( 0 ); mLogger.log( "Selected entry " + selected, LogManager.DEBUG_MESSAGE_LEVEL ); FileServer destDirServer = this.getScratchFileServer( stagingSite ); String destURLPrefix = destDirServer.getURLPrefix(); //figure out the directory where to stage the data //data will be staged to the staging site corresponding to //the execution site and also pick up a FileServer accordingly String baseRemoteWorkDir = null; String baseRemoteWorkDirURL = null;//externally accessible URL if( workerNodeExecution ){ //for pegasus-lite the worker package goes //to the submit directory on the local site. //the staging site is set to local baseRemoteWorkDir = mPOptions.getSubmitDirectory(); baseRemoteWorkDirURL = destDirServer.getURLPrefix() + File.separator + baseRemoteWorkDir; } else{ //sharedfs case baseRemoteWorkDir = siteStore.getInternalWorkDirectory( stagingSite ); baseRemoteWorkDirURL = siteStore.getExternalWorkDirectoryURL( destDirServer, stagingSite ); } if( useFullPath ){ // we insert entries into the transformation catalog for all worker // package executables the planner requires with full paths //this is the shared fs case String name = getRootDirectoryNameForPegasus( selected.getPhysicalTransformation() ); File pegasusHome = new File( baseRemoteWorkDir, name ); StringBuffer sb = new StringBuffer(); sb.append( "Directory where pegasus worker executables will reside on site ").append( stagingSite ). append( " " ).append( pegasusHome.getAbsolutePath() ); mLogger.log( sb.toString(), LogManager.DEBUG_MESSAGE_LEVEL ); mSiteToPegasusHomeMap.put( stagingSite, pegasusHome.getAbsolutePath() ); //now create transformation catalog entry objects for each //worker package executable for( int i = 0; i < PEGASUS_WORKER_EXECUTABLES.length; i++){ TransformationCatalogEntry entry = addDefaultTCEntry( stagingSite, pegasusHome.getAbsolutePath(), selected.getSysInfo(), useFullPath, PEGASUS_WORKER_EXECUTABLES[i][0], PEGASUS_WORKER_EXECUTABLES[i][1] ); mLogger.log( "Entry constructed " + entry , LogManager.DEBUG_MESSAGE_LEVEL ); } } else{ // we insert entries into the transformation catalog for all worker // package executables the planner requires with relative paths // and for the execution sites instead of staging site //this is the PegasusLite case //now create transformation catalog entry objects for each //worker package executable for( int i = 0; i < PEGASUS_WORKER_EXECUTABLES.length; i++){ TransformationCatalogEntry entry = addDefaultTCEntry( site, null, selected.getSysInfo(), useFullPath, PEGASUS_WORKER_EXECUTABLES[i][0], PEGASUS_WORKER_EXECUTABLES[i][1] ); mLogger.log( "Entry constructed " + entry , LogManager.DEBUG_MESSAGE_LEVEL ); } } //create the File Transfer object for shipping the worker executable String sourceURL = selected.getPhysicalTransformation(); FileTransfer ft = new FileTransfer( COMPLETE_TRANSFORMATION_NAME, null ); ft.addSource( selected.getResourceId(), sourceURL ); String baseName = sourceURL.substring( sourceURL.lastIndexOf( "/" ) + 1 ); //figure out the URL prefix depending on //the TPT configuration boolean localTransfer = this.runTransferOnLocalSite( mDefaultTransferRefiner, stagingSite, destURLPrefix, Job.STAGE_IN_JOB); if( localTransfer ){ //then we use the external work directory url ft.addDestination( stagingSite, baseRemoteWorkDirURL + File.separator + baseName ); } else{ ft.addDestination( stagingSite, "file://" + new File( baseRemoteWorkDir, baseName ).getAbsolutePath() ); } if( workerNodeExecution ){ //populate the map with the submit directory locations workerPackageMap.put( site, new File( baseRemoteWorkDir, baseName ).getAbsolutePath() ); } mFTMap.put( site, ft ); mLocalTransfers.put( stagingSite, localTransfer ); } //for pegasus lite and worker package execution //we add the worker package map to PegasusBag if( workerNodeExecution ){ mBag.add( PegasusBag.WORKER_PACKAGE_MAP, workerPackageMap ); } } /** * Returns whether to run a transfer job on local site or not. * * * @param site the site handle associated with the destination URL. * @param destURL the destination URL * @param type the type of transfer job for which the URL is being constructed. * * @return true indicating if the associated transfer job should run on local * site or not. */ public boolean runTransferOnLocalSite( Refiner refiner, String site, String destinationURL, int type) { //check if user has specified any preference in config boolean result = true; //short cut for local site if( site.equals( "local" ) ){ //transfer to run on local site return result; } if( refiner.runTransferRemotely( site, type )){ //always use user preference return !result; } //check to see if destination URL is a file url else if( destinationURL != null && destinationURL.startsWith( PegasusURL.FILE_URL_SCHEME ) ){ result = false; } return result; } /** * Does regex magic to figure out the version of pegasus from the url, and * use it to construct the name of pegasus directory, when worker package * is untarred. * * @param url the url. * * @return basename for pegasus directory */ protected String getRootDirectoryNameForPegasus( String url ){ StringBuffer result = new StringBuffer(); result.append( "pegasus-" ); //compile the pattern only once. if( mPattern == null ){ mPattern = Pattern.compile( mRegexExpression ); } String base = url.substring( url.lastIndexOf( "/" ) + 1 ); mLogger.log( "Base is " + base, LogManager.DEBUG_MESSAGE_LEVEL ); Matcher matcher = mPattern.matcher( base ); String version = null; if( matcher.matches() ){ version = matcher.group(3); } else{ throw new RuntimeException( "Unable to determine pegasus version from url " + url ); } mLogger.log( "Version is " + version, LogManager.DEBUG_MESSAGE_LEVEL ); result.append( version ); return result.toString(); } /** * Determines the sysinfo from the name of a worker package * * @param name the name * * @return SysInfo matching the worker package created */ protected SysInfo determineSysInfo( String name ){ SysInfo result = new SysInfo(); //compile the pattern only once. if( mPattern == null ){ mPattern = Pattern.compile( mRegexExpression ); } Matcher matcher = mPattern.matcher( name ); String version = null; if( matcher.matches() ){ result.setArchitecture(SysInfo.Architecture.valueOf(matcher.group(4))); result.setOSRelease( matcher.group(5) ); result.setOSVersion( matcher.group(6)); } else{ throw new RuntimeException( "Unable to determine system information of package from name " + name ); } //guess the main OS String osrelease = result.getOSRelease(); if( osrelease.startsWith( "rhel" ) || osrelease.startsWith( "deb" ) || osrelease.startsWith( "ubuntu" ) || osrelease.startsWith( "fc" ) || osrelease.startsWith( "suse" ) ){ result.setOS(SysInfo.OS.linux ); } else if( osrelease.startsWith( "macos" ) ){ result.setOS(SysInfo.OS.macosx ); } mLogger.log( "System information for " + name + " is " + result, LogManager.DEBUG_MESSAGE_LEVEL ); return result; } /** * Adds a setup node per execution site in the workflow that will stage the * worker node executables to the workdirectory on the sites the workflow * has been scheduled to. * * @param dag the scheduled workflow. * * @return the workflow with setup jobs added */ public ADag addSetupNodes( ADag dag ){ Mapper m = mBag.getHandleToTransformationMapper(); //PM-833 we need to instantiate the setup tx implementation //to ensure it has the right submit directory creator associated //load the transfer setup implementation mSetupTransferImplementation = ImplementationFactory.loadInstance( this.mBag, ImplementationFactory.TYPE_SETUP ); mSetupTransferImplementation.setRefiner( mDefaultTransferRefiner ); //boolean addUntarJobs = !mWorkerNodeExecution; Set[] deploymentSites = this.getDeploymentSites( dag ); if( !mTransferWorkerPackage && ( deploymentSites[1].isEmpty() ) ){ //PM-810 user specified property is false for worker package //and nonsharedfs|condorio deployment is empty mLogger.log( "No Deployment of Worker Package needed" , LogManager.DEBUG_MESSAGE_LEVEL ); return dag; } if( mTransferWorkerPackage && !deploymentSites[0].isEmpty() ){ //PM-810 for sharedfs case, worker package transfer can only happen //if the property is set by the user in the proeprties file //we add untar nodes only if worker node execution/pegasus lite //mode is disabled dag =addSetupNodesWithUntarNodes( dag , deploymentSites[0] );//non pegasus lite case. shared fs } if( !deploymentSites[1].isEmpty() ){ dag = addSetupNodesWithoutUntarNodes( dag, deploymentSites[1] ); } return dag; } /** * Adds untar nodes to the workflow, in addition to the stage worker nodes * * @param dag the dag * @param deploymentSites the sites for which the worker package has to be deployed * * @return the workflow in the graph representation with the nodes added. */ private ADag addSetupNodesWithUntarNodes( ADag dag, Set<String> deploymentSites ) { //convert the dag to a graph representation and walk it //in a top down manner //PM-747 no need for conversion as ADag now implements Graph interface ADag workflow = dag; //get the root nodes of the workflow List<GraphNode> roots = workflow.getRoots(); //add a setup job per execution site for( Iterator it = deploymentSites.iterator(); it.hasNext(); ){ String site = ( String ) it.next(); //for pegauss lite mode the staging site for worker package //should be local site , submit directory. //String stagingSite = this.getStagingSite(site); String stagingSite = site; //PM-810 mLogger.log( "Adding worker package deployment node for " + site + " and staging site as " + stagingSite, LogManager.DEBUG_MESSAGE_LEVEL ); FileTransfer ft = (FileTransfer)mFTMap.get( site ); List<FileTransfer> fts = new ArrayList<FileTransfer>(1); fts.add( ft ); //hmm need to propogate site info with a dummy job on fly Job dummy = new Job() ; dummy.setSiteHandle( site ); //stage worker job runs locally or on the staging site boolean localTransfer = mLocalTransfers.get( stagingSite ) ; String tsite = localTransfer? "local" : stagingSite; TransferJob setupTXJob = mSetupTransferImplementation.createTransferJob( dummy, tsite, fts, null, this.getDeployJobName( dag, site , localTransfer), Job.STAGE_IN_WORKER_PACKAGE_JOB ); //the setupTXJob non third party site, has to be the staging site setupTXJob.setNonThirdPartySite( stagingSite ); //the setup and untar jobs need to be launched without kickstart. setupTXJob.vdsNS.construct( Pegasus.GRIDSTART_KEY, "None" ); //no empty postscript but arguments to exitcode to add -r $RETURN setupTXJob.dagmanVariables.construct( Dagman.POST_SCRIPT_KEY, PegasusExitCode.SHORT_NAME ); setupTXJob.dagmanVariables.construct( Dagman.POST_SCRIPT_ARGUMENTS_KEY, POSTSCRIPT_ARGUMENTS_FOR_ONLY_ROTATING_LOG_FILE ); GraphNode setupNode = new GraphNode( setupTXJob.getName(), setupTXJob ); //add the untar job Job untarJob = this.makeUntarJob( stagingSite, this.getUntarJobName( dag, site ), getBasename( ((NameValue)ft.getSourceURL()).getValue() ) ); untarJob.vdsNS.construct( Pegasus.GRIDSTART_KEY, "None" ); untarJob.dagmanVariables.construct( Dagman.POST_SCRIPT_KEY, PegasusExitCode.SHORT_NAME ); untarJob.dagmanVariables.construct( Dagman.POST_SCRIPT_ARGUMENTS_KEY, POSTSCRIPT_ARGUMENTS_FOR_ONLY_ROTATING_LOG_FILE ); GraphNode untarNode = new GraphNode( untarJob.getName(), untarJob ); //untar node is child of setup setupNode.addChild( untarNode ); untarNode.addParent( setupNode ); //add the original roots as children to untar node for( Iterator<GraphNode> rIt = roots.iterator(); rIt.hasNext(); ){ GraphNode n = ( GraphNode ) rIt.next(); mLogger.log( "Added edge " + untarNode.getID() + " -> " + n.getID(), LogManager.DEBUG_MESSAGE_LEVEL ); untarNode.addChild( n ); n.addParent( untarNode ); } workflow.addNode( untarNode ); workflow.addNode( setupNode ); } return workflow; } /** * Adds only the stage worker nodes to the workflow. This is used when * Pegasus Lite is used to launch the jobs on the execution sites. * * @param dag the dag * @param deploymentSites the sites for which the worker package has to be deployed * * @return the workflow in the graph representation with the nodes added. */ private ADag addSetupNodesWithoutUntarNodes( ADag dag, Set<String> deploymentSites ) { //convert the dag to a graph representation and walk it //in a top down manner //PM-747 no need for conversion as ADag now implements Graph interface ADag workflow = dag ; //get the root nodes of the workflow List<GraphNode> roots = workflow.getRoots(); Set<FileTransfer> fts = new HashSet<FileTransfer>(); //for pegauss lite mode the staging site for worker package //should be local site , submit directory. String stagingSite = "local"; if( deploymentSites.isEmpty() ){ //PM-706 in case of condorio and full workflow reduction mLogger.log( "Skipping staging of worker package as no deployment site detected ", LogManager.INFO_MESSAGE_LEVEL ); return workflow; } //stage worker job runs locally or on the staging site //PM-706 check for null returns boolean localTransfer = mLocalTransfers.containsKey( stagingSite) ? mLocalTransfers.get( stagingSite ) : true; //add a setup job per execution site for( Iterator it = deploymentSites.iterator(); it.hasNext(); ){ String site = ( String ) it.next(); mLogger.log( "Adding worker package deployment node for " + site, LogManager.DEBUG_MESSAGE_LEVEL ); FileTransfer ft = (FileTransfer)mFTMap.get( site ); //PM-1127 do an extra site if both source and destination //site match and are set to local NameValue source = ft.getSourceURL(); NameValue destination = ft.getSourceURL(); if( source.getKey().equals( destination.getKey()) && source.getKey().equals( "local") ){ //make sure the full canonical urls are different //only if source and destination urls both are file String sourceURL = source.getValue(); String destURL = destination.getValue(); if( sourceURL.startsWith( PegasusURL.FILE_URL_SCHEME ) && destURL.startsWith( PegasusURL.FILE_URL_SCHEME ) ){ try { //do the actual canonical check to make sure if the stage worker job //should not be added if( new File(sourceURL).getCanonicalPath().equals( new File(destURL).getCanonicalPath()) ){ mLogger.log( "Skipping stage worker job for site " + site + " as worker package already in submit directory " + sourceURL, LogManager.DEBUG_MESSAGE_LEVEL ); continue; } } catch (IOException ex) { mLogger.log( "Error in Canonical compare for " + ft , ex, LogManager.ERROR_MESSAGE_LEVEL); } } } //add the file transfer for stage worker job fts.add( ft ); }//end of for loop if( fts.isEmpty() ){ //PM-1127 no file transfer to be done for stage worker job //return the workflow unmodified return workflow; } //hmm need to propogate site info with a dummy job on fly Job dummy = new Job() ; dummy.setSiteHandle( stagingSite ); String tsite = "local" ; TransferJob setupTXJob = mSetupTransferImplementation.createTransferJob( dummy, tsite, fts, null, this.getDeployJobName( dag, tsite , localTransfer), Job.STAGE_IN_WORKER_PACKAGE_JOB ); //the setupTXJob is null as stage worker job pulls in //data to the submit host directory setupTXJob.setNonThirdPartySite( null ); //the setup and untar jobs need to be launched without kickstart. setupTXJob.vdsNS.construct( Pegasus.GRIDSTART_KEY, "None" ); //no empty postscript but arguments to exitcode to add -r $RETURN setupTXJob.dagmanVariables.construct( Dagman.POST_SCRIPT_ARGUMENTS_KEY, POSTSCRIPT_ARGUMENTS_FOR_ONLY_ROTATING_LOG_FILE ); GraphNode setupNode = new GraphNode( setupTXJob.getName(), setupTXJob ); //add the original roots as children to setup node for( Iterator rIt = roots.iterator(); rIt.hasNext(); ){ GraphNode n = ( GraphNode ) rIt.next(); mLogger.log( "Added edge " + setupNode.getID() + " -> " + n.getID(), LogManager.DEBUG_MESSAGE_LEVEL ); setupNode.addChild( n ); n.addParent( setupNode ); } workflow.addNode( setupNode ); return workflow; } /** * Retrieves the sites for which the deployment jobs need to be created. * * @param dag the dag on which the jobs need to execute. * * @return a Set array containing a list of siteID's of the sites where the * dag has to be run. Index[0] has the sites for sharedfs deployment * while Index[1] for ( nonsharedfs and condorio). */ protected Set[] getDeploymentSites( ADag dag ){ Set[] result = new Set[2]; result[0] = new HashSet(); result[1] = new HashSet(); Set sharedFSSet = result[0]; Set nonsharedFSSet = result[1]; for(Iterator<GraphNode> it = dag.jobIterator();it.hasNext();){ GraphNode node = it.next(); Job job = (Job)node.getContent(); //PM-497 //we ignore any clean up jobs that may be running if( job.getJobType() == Job.CLEANUP_JOB || ( job.getJobType() == Job.STAGE_IN_JOB || job.getJobType() == Job.STAGE_OUT_JOB || job.getJobType() == Job.INTER_POOL_JOB )){ //we also ignore any remote transfer jobs that maybe associated to run in the work directory //because of the fact that staging site may have a file server URL. continue; } //add to the set only if the job is //being run in the work directory //this takes care of local site create dir String conf = job.vdsNS.getStringValue( Pegasus.DATA_CONFIGURATION_KEY); if( conf != null && job.runInWorkDirectory()){ if( conf.equalsIgnoreCase( PegasusConfiguration.SHARED_FS_CONFIGURATION_VALUE) ){ sharedFSSet.add( job.getSiteHandle() ); } else{ nonsharedFSSet.add( job.getSiteHandle() ); } } } //PM-810 sanity check to make sure sites are not setup //for both modes Set<String> intersection = new HashSet<String>( sharedFSSet ); intersection.retainAll( nonsharedFSSet ); if( !intersection.isEmpty() ){ throw new RuntimeException( "Worker package is set to be staged for both sharedfs and nonsharedfs|condorio mode for sites " + intersection ); } //remove the stork pool sharedFSSet.remove("stork"); nonsharedFSSet.remove( "stork" ); return result; } /** * It returns the name of the deployment job, that is to be assigned. * The name takes into account the workflow name while constructing it, as * that is thing that can guarentee uniqueness of name in case of deferred * planning. * * @param dag the workflow so far. * @param site the execution pool for which the create directory job * is responsible. * @param localTransfer whether the transfer needs to run locally or not. * * @return String corresponding to the name of the job. */ protected String getDeployJobName( ADag dag, String site , boolean localTransfer ){ StringBuffer sb = new StringBuffer(); //append setup prefix sb.append( DeployWorkerPackage.DEPLOY_WORKER_PREFIX ); if( localTransfer ){ sb.append( Refiner.LOCAL_PREFIX ); } else{ sb.append( Refiner.REMOTE_PREFIX ); } //append the job prefix if specified in options at runtime if ( mJobPrefix != null ) { sb.append( mJobPrefix ); } sb.append( dag.getLabel() ).append( "_" ). append( dag.getIndex() ).append( "_" ); sb.append( site ); return sb.toString(); } /** * It returns the name of the untar job, that is to be assigned. * The name takes into account the workflow name while constructing it, as * that is thing that can guarentee uniqueness of name in case of deferred * planning. * * @param dag the workflow so far. * @param site the execution pool for which the create directory job * is responsible. * * @return String corresponding to the name of the job. */ protected String getUntarJobName( ADag dag, String site ){ StringBuffer sb = new StringBuffer(); //append setup prefix sb.append( DeployWorkerPackage.UNTAR_PREFIX ); //append the job prefix if specified in options at runtime if ( mJobPrefix != null ) { sb.append( mJobPrefix ); } sb.append( dag.getLabel() ).append( "_" ). append( dag.getIndex() ).append( "_" ); sb.append( site ); return sb.toString(); } /** * It returns the name of the untar job, that is to be assigned. * The name takes into account the workflow name while constructing it, as * that is thing that can guarentee uniqueness of name in case of deferred * planning. * * @param dag the workflow so far. * @param site the execution pool for which the create directory job * is responsible. * * @return String corresponding to the name of the job. */ protected String getCleanupJobname( ADag dag, String site ){ StringBuffer sb = new StringBuffer(); //append setup prefix sb.append( DeployWorkerPackage.CLEANUP_PREFIX ); //append the job prefix if specified in options at runtime if ( mJobPrefix != null ) { sb.append( mJobPrefix ); } sb.append( dag.getLabel() ).append( "_" ). append( dag.getIndex() ).append( "_" ); sb.append( site ); return sb.toString(); } /** * It creates a untar job , that untars the worker package that is staged * by the setup transfer job. * * @param site the execution pool for which the create dir job is to be * created. * @param jobName the name that is to be assigned to the job. * @param wpBasename the basename of the worker package that is staged to remote site. * * @return create dir job. */ protected Job makeUntarJob( String site, String jobName, String wpBasename ) { Job newJob = new Job(); List entries = null; String execPath = null; TransformationCatalogEntry entry = null; // GridGateway jobManager = null; try { entries = mTCHandle.lookup( DeployWorkerPackage.UNTAR_TRANSFORMATION_NAMESPACE, DeployWorkerPackage.UNTAR_TRANSFORMATION_NAME, DeployWorkerPackage.UNTAR_TRANSFORMATION_VERSION, site, TCType.INSTALLED); } catch (Exception e) { //non sensical catching mLogger.log("Unable to retrieve entries from TC " + e.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL ); } entry = ( entries == null ) ? this.defaultUntarTCEntry( mSiteStore.lookup(site) ): //try using a default one (TransformationCatalogEntry) entries.get(0); if( entry == null ){ //NOW THROWN AN EXCEPTION //should throw a TC specific exception StringBuffer error = new StringBuffer(); error.append("Could not find entry in tc for lfn "). append( DeployWorkerPackage.COMPLETE_UNTAR_TRANSFORMATION_NAME ). append(" at site ").append( site ); mLogger.log( error.toString(), LogManager.ERROR_MESSAGE_LEVEL); throw new RuntimeException( error.toString() ); } execPath = entry.getPhysicalTransformation(); SiteCatalogEntry ePool = mSiteStore.lookup( site ); //String argString = "zxvf " + wpBasename; // tar -C /tmp/ -zxvf pegasus-worker-2.4.0dev-x86_rhas_3.tar.gz //we want to fully specify the directory where we want tar file //untarred StringBuffer arguments = new StringBuffer(); arguments.append( " -C " ).append( mSiteStore.getInternalWorkDirectory( site ) ). append( " -zxvf " ).append( mSiteStore.getInternalWorkDirectory( site ) ). append( File.separator ).append( wpBasename ); newJob.jobName = jobName; newJob.setTransformation( DeployWorkerPackage.UNTAR_TRANSFORMATION_NAMESPACE, DeployWorkerPackage.UNTAR_TRANSFORMATION_NAME, DeployWorkerPackage.UNTAR_TRANSFORMATION_VERSION ); newJob.setDerivation( DeployWorkerPackage.UNTAR_DERIVATION_NAMESPACE, DeployWorkerPackage.UNTAR_DERIVATION_NAME, DeployWorkerPackage.UNTAR_DERIVATION_VERSION ); newJob.executable = execPath; newJob.executionPool = site; //PM-845 set staging site handle to same as execution site of compute job newJob.setStagingSiteHandle(site); newJob.strargs = arguments.toString(); //for JIRA PM-38 we used to run as a compute job //this creates problem with stampede schema as the job is counted //towards a dax task. the untar job is classified as chmod job //internally now. JIRA PM-326 newJob.jobClass = Job.CHMOD_JOB; newJob.jobID = jobName; //the profile information from the pool catalog needs to be //assimilated into the job. newJob.updateProfiles( ePool.getProfiles() ); //add any notifications specified in the transformation //catalog for the job. JIRA PM-391 newJob.addNotifications( entry ); //the profile information from the transformation //catalog needs to be assimilated into the job //overriding the one from pool catalog. newJob.updateProfiles(entry); //the profile information from the properties file //is assimilated overidding the one from transformation //catalog. newJob.updateProfiles(mProps); return newJob; } /** * Returns a default TC entry to be used in case entry is not found in the * transformation catalog. It also attempts to add the transformation catalog * entry to the underlying TC store. * * @param site the site for which the default entry is required. * @param pegasusHome the path to deployed worker package * @param sysinfo the system information of that site. * @param useFullPath boolean indicating whether to use just the basename or * the full path * @param name the logical name of the transformation * @param executable the basename of the executable * * * @return the default entry. */ private TransformationCatalogEntry addDefaultTCEntry( String site, String pegasusHome, SysInfo sysinfo, boolean useFullPath, String name, String executable ){ TransformationCatalogEntry defaultTCEntry = null; mLogger.log( "Creating a default TC entry for " + Separator.combine( "pegasus", name, null ) + " at site " + site, LogManager.DEBUG_MESSAGE_LEVEL ); //construct the path to the executable StringBuffer path = new StringBuffer(); if( useFullPath ){ path.append( pegasusHome ).append( File.separator ). append( "bin" ).append( File.separator ); } path.append( executable ); mLogger.log( "Remote Path set is " + path.toString(), LogManager.DEBUG_MESSAGE_LEVEL ); defaultTCEntry = new TransformationCatalogEntry( "pegasus", name , null ); defaultTCEntry.setPhysicalTransformation( path.toString() ); defaultTCEntry.setResourceId( site ); defaultTCEntry.setType( TCType.INSTALLED ); defaultTCEntry.setSysInfo( sysinfo ); if( useFullPath ){ //add pegasus home as an environment variable defaultTCEntry.addProfile( new Profile( Profile.ENV, "PEGASUS_HOME", pegasusHome )); } //register back into the transformation catalog //so that we do not need to worry about creating it again try{ mTCHandle.insert( defaultTCEntry , false ); } catch( Exception e ){ //just log as debug. as this is more of a performance improvement //than anything else mLogger.log( "Unable to register in the TC the default entry " + defaultTCEntry.getLogicalTransformation() + " for site " + site, e, LogManager.ERROR_MESSAGE_LEVEL ); //throw exception as throw new RuntimeException( e ); } return defaultTCEntry; } /** * Returns a transformation catalog entry to be used for the pegasus worker * package location. The following rules are followed for determining the * entry * <pre> * - if a pegasus::worker entry exists in the trasnformation catalog for the site, it is used * - else, the worker package based on the submit host install is used if * a) user specified osrelease for the site in the site catalog and there is a * complete match for sysinfo ( os, osrelease, version, and arch) * with the submit host wp OR * b) just the OS and architecture of remote site matches the submit host created worker package * - else, the worker package is pulled from the Pegasus website. * </pre> * * @param mapper * @param selector * @param site the execution site for which we need a matching static binary. * @param workerNodeExecution boolean indicating whether worker package is * staged to compute site via a staging site or not. * * * * @return the default entry. */ protected TransformationCatalogEntry getTCEntryForPegasusWorkerPackage( Mapper mapper, TransformationSelector selector, String site, boolean workerNodeExecution) { //check if there is a valid entry for worker package List<TransformationCatalogEntry> entries, selectedEntries = null; try{ entries = mapper.getTCList( DeployWorkerPackage.TRANSFORMATION_NAMESPACE, DeployWorkerPackage.TRANSFORMATION_NAME, DeployWorkerPackage.TRANSFORMATION_VERSION, site ); selectedEntries = selector.getTCEntry( entries ); }catch( Exception e ){ /*ignore*/} if( selectedEntries != null && selectedEntries.size() > 0 ){ //PM-888 //We prefer whatever a user wants us to use as a worker package //we return the first selection. return selectedEntries.get(0); } TransformationCatalogEntry entry = null; //check to see if the one created on the submit host is //suffficient to use for the site. SysInfo remoteSiteSysInfo = mSiteStore.getSysInfo( site ); SysInfo submitHostSysInfo = this.determineSysInfo( this.mSubmitHostWorkerPackage.getName() ); mLogger.log( "Compute site sysinfo " + site + " " + remoteSiteSysInfo , LogManager.DEBUG_MESSAGE_LEVEL); boolean useSubmitHostWF = false; if( remoteSiteSysInfo.getOSRelease() != null && remoteSiteSysInfo.getOSRelease().length() > 0 ){ if (remoteSiteSysInfo.equals( submitHostSysInfo )){ //user has specified a specific architecture in the site catalog //we can only use the worker package created on the submit host, if //they match completely useSubmitHostWF = true; } } else{ //osrelease is not specified. //just do a shallow match on OS and architecture if( remoteSiteSysInfo.getOS().equals( submitHostSysInfo.getOS() ) && remoteSiteSysInfo.getArchitecture().equals( submitHostSysInfo.getArchitecture() )){ useSubmitHostWF = true; } } if( useSubmitHostWF ){ //sanity check to see if a transfer of the worker package from //local site to compute site will even work based on scratch //dir url of compute site. we do this check only if stage worker //job has to transfer package to the compute site and not to a //staging site if( !site.equals( "local") && !workerNodeExecution ){ //need to check for the site scratch dir url FileServer stagingSiteServer = this.getScratchFileServer(site); if( stagingSiteServer.getURLPrefix().startsWith( PegasusURL.FILE_URL_SCHEME) ){ //if staging site is a file URL then we disable //using the worker package created on the submit host mLogger.log( "Not using the worker package from the submit host install " + mSubmitHostWorkerPackage + " The scratch file server is a file url scheme for compute site " + site, LogManager.DEBUG_MESSAGE_LEVEL ); useSubmitHostWF = false; } } } if( useSubmitHostWF ){ //create a default transformation catalog entry for the submit host location entry = new TransformationCatalogEntry( DeployWorkerPackage.TRANSFORMATION_NAMESPACE, DeployWorkerPackage.TRANSFORMATION_NAME , null ); entry.setPhysicalTransformation( PegasusURL.FILE_URL_SCHEME + "//" + mSubmitHostWorkerPackage ); entry.setResourceId( "local" ); entry.setType( TCType.STAGEABLE ); //we deliberately set the sysinfo for this to be the remote site //so that it allows for exact matches later on entry.setSysInfo( remoteSiteSysInfo ); } else{ //try and create a default entry for pegasus::worker if entry = this.getDefaultTCEntryForPegasusWorkerPackage( site ); if( entry == null ){ StringBuffer error = new StringBuffer(); error.append( "Unable to construct default entry for pegasus::worker for site " ).append( site ) .append( " Add entry in TC for pegasus::worker of type STAGEABLE for sysinfo ") .append( mSiteStore.getSysInfo( site ) ); throw new RuntimeException( error.toString() ); } } return entry; } /** * Returns a default TC entry for the Pegasus worker package from the * Pegasus website. The entry points to * the http webserver on the pegasus website. It also attempts to add * the transformation catalog entry to the TC store. * * @param site the execution site for which we need a matching static binary. * * * @return the default entry. */ protected TransformationCatalogEntry getDefaultTCEntryForPegasusWorkerPackage( String site ){ TransformationCatalogEntry defaultTCEntry = null; //String site = "pegasus"; SysInfo sysinfo = mSiteStore.getSysInfo( site ); if( sysinfo == null ){ mLogger.log( "Unable to get System Information for site " + site, LogManager.ERROR_MESSAGE_LEVEL ); return null; } //construct the path to the executable String path = constructDefaultURLToPegasusWorkerPackage( DeployWorkerPackage.TRANSFORMATION_NAME, sysinfo ); if( path == null ){ mLogger.log( "Unable to determine path for worker package for " + sysinfo, LogManager.DEBUG_MESSAGE_LEVEL ); return null; } mLogger.log( "Creating a default TC entry for " + Separator.combine( "pegasus", DeployWorkerPackage.TRANSFORMATION_NAME, null ) + " at site pegasus for sysinfo " + sysinfo, LogManager.DEBUG_MESSAGE_LEVEL ); mLogger.log( "Remote Path set is " + path.toString(), LogManager.DEBUG_MESSAGE_LEVEL ); defaultTCEntry = new TransformationCatalogEntry( DeployWorkerPackage.TRANSFORMATION_NAMESPACE, DeployWorkerPackage.TRANSFORMATION_NAME , null ); defaultTCEntry.setPhysicalTransformation( path ); defaultTCEntry.setResourceId( "pegasus" ); defaultTCEntry.setType( TCType.STAGEABLE ); defaultTCEntry.setSysInfo( sysinfo ); return defaultTCEntry; } /** * Constructs the default URL's for the pegasus worker package. If the user * has not specified the URL to the source directory in Pegaus Properties then * the URL constructed points to the pegasus website. * * The version of Pegasus retrieved is the one against which the planner * is executing. * * @param name the logical name of the executable, usually worker|binary. * @param sysinfo the sysinfo for which the path is required. * * @return url */ protected String constructDefaultURLToPegasusWorkerPackage( String name, SysInfo sysinfo ) { //get the matching architecture //String arch = ( String )DeployWorkerPackage.archToNMIArch().get( sysinfo.getArch() ); String arch = sysinfo.getArchitecture().toString(); //PM-732 lets figure out if a user has specified an OS release or OS version //or not String osRelease = sysinfo.getOSRelease(); String osVersion = sysinfo.getOSVersion(); //for mac there is only single OSRelease osRelease = ( sysinfo.getOS() == SysInfo.OS.macosx ) ? "macos" : osRelease; String osReleaseAndVersion = null; if ( ( osRelease != null && osRelease.length() != 0 ) && ( osVersion != null && osVersion.length() != 0 ) ){ //if both os release and version are specified by user //then we know user is being specific. check to see if it //is built by our built system osReleaseAndVersion = osRelease + "_" + osVersion; if( !DeployWorkerPackage.supportedOSReleaseAndVersions().contains(osReleaseAndVersion) ){ //set back to null and log a warning mLogger.log( "Worker Package Deployment: Unsupported os release and version " + osReleaseAndVersion + " for OS " + sysinfo.getOS() + " . Will rely on default package for the OS.", LogManager.WARNING_MESSAGE_LEVEL ); osReleaseAndVersion = null; } } //if osReleaseAndVersion is null, then construct a default one based on OS if( osReleaseAndVersion == null){ osReleaseAndVersion = ( String )DeployWorkerPackage.osToOSReleaseAndVersion().get( sysinfo.getOS() ); } if( arch == null || osReleaseAndVersion == null ){ mLogger.log( "Unable to construct url for pegasus worker for " + sysinfo , LogManager.DEBUG_MESSAGE_LEVEL ); return null; } StringBuffer url = new StringBuffer(); //construct the base path if( mUseUserSpecifiedSourceLocation ){ url.append( mUserSpecifiedSourceLocation ).append( File.separator); } else{ url.append( DeployWorkerPackage.BASE_BUILD_DIRECTORY_URL ). append( PEGASUS_VERSION ).append( "/" ); } url.append( "pegasus-" ).append( name ).append( "-" ). append( PEGASUS_VERSION ).append( "-" ). append( arch ).append( "_" ). append( osReleaseAndVersion ).append( ".tar.gz" ); return url.toString(); } /** * Returns a default TC entry to be used in case entry is not found in the * transformation catalog. * * @param site the site for which the default entry is required. * * * @return the default entry. */ private TransformationCatalogEntry defaultUntarTCEntry( SiteCatalogEntry site ){ TransformationCatalogEntry defaultTCEntry = null; mLogger.log( "Creating a default TC entry for " + DeployWorkerPackage.COMPLETE_UNTAR_TRANSFORMATION_NAME + " at site " + site, LogManager.DEBUG_MESSAGE_LEVEL ); //construct the path to the executable StringBuffer path = new StringBuffer(); path.append( "/bin/tar" ); mLogger.log( "Remote Path set is " + path.toString(), LogManager.DEBUG_MESSAGE_LEVEL ); defaultTCEntry = new TransformationCatalogEntry( DeployWorkerPackage.UNTAR_TRANSFORMATION_NAMESPACE, DeployWorkerPackage.UNTAR_TRANSFORMATION_NAME , DeployWorkerPackage.UNTAR_TRANSFORMATION_VERSION ); defaultTCEntry.setPhysicalTransformation( path.toString() ); defaultTCEntry.setResourceId( site.getSiteHandle() ); defaultTCEntry.setType( TCType.INSTALLED ); defaultTCEntry.setSysInfo( site.getSysInfo()); //add path as an environment variable //addDefaultTCEntry.addProfile( new Profile( Profile.ENV, "PATH", DeployWorkerPackage.PATH_VALUE )); //register back into the transformation catalog //so that we do not need to worry about creating it again try{ mTCHandle.insert( defaultTCEntry , false ); } catch( Exception e ){ //just log as debug. as this is more of a performance improvement //than anything else mLogger.log( "Unable to register in the TC the default entry " + defaultTCEntry.getLogicalTransformation() + " for site " + site, e, LogManager.ERROR_MESSAGE_LEVEL ); //throw exception as throw new RuntimeException( e ); } return defaultTCEntry; } /** * Returns the basename of the URL using substring. * * @param url * * @return basename */ protected String getBasename( String url ){ return ( url == null || url.length() == 0 )? null: url.substring( url.lastIndexOf( File.separator ) + 1 ); } /** * A convenience method to return a scratch file server on a staging site. * The method ensures that FileServer is populated sufficiently with the url * prefix * * @param site * * @return FileServer * * @throws RuntimeException when URL Prefix cannot be determined for various reason. */ protected FileServer getScratchFileServer( String site ){ SiteCatalogEntry stagingSiteEntry = this.mSiteStore.lookup( site ); FileServer fileServer = ( stagingSiteEntry == null )? null: stagingSiteEntry.selectHeadNodeScratchSharedFileServer( FileServer.OPERATION.put ); String destURLPrefix = ( fileServer == null )? null: fileServer.getURLPrefix(); if( destURLPrefix == null ){ this.complainForHeadNodeURLPrefix( REFINER_NAME, site , FileServer.OPERATION.put); } return fileServer; } }