/** * Copyright 2007-2015 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.common; import edu.isi.pegasus.common.logging.LogManager; import edu.isi.pegasus.common.logging.LogManagerFactory; import edu.isi.pegasus.common.util.DefaultStreamGobblerCallback; import edu.isi.pegasus.common.util.FindExecutable; import edu.isi.pegasus.common.util.StreamGobbler; import edu.isi.pegasus.planner.classes.ADag; import edu.isi.pegasus.planner.classes.PegasusBag; import edu.isi.pegasus.planner.classes.PlannerOptions; import edu.isi.pegasus.planner.code.CodeGeneratorException; import edu.isi.pegasus.planner.code.generator.Braindump; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * Helper class to call out to pegasus-db-admin to check out the * status of various Pegasus databases. * * @author Karan Vahi */ public class PegasusDBAdmin { public static final String MASTER_DATABASE_PROPERTY_KEY = "pegasus.catalog.master.url"; public static final String MASTER_DATABASE_DEPRECATED_PROPERTY_KEY = "pegasus.dashboard.output"; public static final String WORKFLOW_DATABASE_PROPERTY_KEY = "pegasus.catalog.workflow.url"; public static final String WORKFLOW_DATABASE_DEPRECATED_PROPERTY_KEY = "pegasus.monitord.output"; private static enum DB_ADMIN_COMMANDS { create, downgrade, update, check, version }; /** * */ public static void updateProperties(PegasusBag bag, ADag workflow ) { PegasusProperties properties = bag.getPegasusProperties(); PlannerOptions options = bag.getPlannerOptions(); String url = properties.getProperty( MASTER_DATABASE_PROPERTY_KEY ); if( url == null ){ //check for deprecated url = properties.getProperty( MASTER_DATABASE_DEPRECATED_PROPERTY_KEY ); } if( url == null ){ //construct default path //construct default sb for master workflow database StringBuilder sb = new StringBuilder(); sb.append( "sqlite:///" ).append( System.getProperty("user.home") ). append( File.separator ).append( ".pegasus" ). append( File.separator ).append( "workflow.db" ); url = sb.toString(); } //set the property back properties.setProperty( MASTER_DATABASE_PROPERTY_KEY, url); //update the workflow database url property url = properties.getProperty( WORKFLOW_DATABASE_PROPERTY_KEY ); if( url == null ){ //check for deprecated url = properties.getProperty( WORKFLOW_DATABASE_DEPRECATED_PROPERTY_KEY ); } if( url == null ){ Braindump bd = new Braindump(); Map<String,String> entries = new HashMap(); try { bd.initialize( bag ); entries = bd.defaultBrainDumpEntries( workflow ); } catch (CodeGeneratorException ex) { throw new RuntimeException( "Error while generating default braindump entries " , ex ); } String workflowDBBasename = entries.get( Braindump.DAX_LABEL_KEY ) + "-" + entries.get( Braindump.DAX_INDEX_KEY ) + ".stampede.db"; //construct default path //construct default sb for master workflow database StringBuilder sb = new StringBuilder(); sb.append( "sqlite:///" ).append( options.getSubmitDirectory() ). append( File.separator ).append( workflowDBBasename ); url = sb.toString(); } //set the property back properties.setProperty( WORKFLOW_DATABASE_PROPERTY_KEY, url); } private LogManager mLogger; private PegasusProperties mProps; public PegasusDBAdmin(){ this( LogManagerFactory.loadSingletonInstance() ); } public PegasusDBAdmin( LogManager logger ){ mLogger = logger; } /** * Calls out to the pegasus-db-admin tool to check and update master database * if required. * * @param propertiesFile * @return */ public boolean checkMasterDatabaseForVersionCompatibility( String propertiesFile ) { StringBuilder arguments = new StringBuilder(); arguments.append( "-t master " ). append( "-c " ).append( propertiesFile ); return this.checkDatabase( DB_ADMIN_COMMANDS.update.name(), arguments.toString() ); } /** * Calls out to the pegasus-db-admin tool to check for jdbrc compatibility. * * @param propertiesFile * @return */ public boolean checkJDBCRCForCompatibility( String propertiesFile ) { StringBuilder arguments = new StringBuilder(); arguments.append( "-t jdbcrc " ). append( "-c " ).append( propertiesFile ); return this.checkDatabase( DB_ADMIN_COMMANDS.check.name(), arguments.toString() ); } public boolean checkDatabase( String dbCommand, String checkDBArguments ){ String basename = "pegasus-db-admin"; File pegasusDBAdmin = FindExecutable.findExec( basename ); if( pegasusDBAdmin == null ){ throw new RuntimeException( "Unable to find path to " + basename ); } //construct arguments for pegasus-db-admin StringBuffer args = new StringBuffer(); args.append( dbCommand ); args.append( " " ).append( checkDBArguments ); String command = pegasusDBAdmin.getAbsolutePath() + " " + args; mLogger.log("Executing " + command, LogManager.DEBUG_MESSAGE_LEVEL ); try{ //set the callback and run the pegasus-run command Runtime r = Runtime.getRuntime(); Process p = r.exec(command ); //spawn off the gobblers with the already initialized default callback StreamGobbler ips = new StreamGobbler( p.getInputStream(), new DefaultStreamGobblerCallback( LogManager.CONSOLE_MESSAGE_LEVEL )); StreamGobbler eps = new StreamGobbler( p.getErrorStream(), new DefaultStreamGobblerCallback( LogManager.ERROR_MESSAGE_LEVEL)); ips.start(); eps.start(); //wait for the threads to finish off ips.join(); eps.join(); //get the status int status = p.waitFor(); mLogger.log( basename + " exited with status " + status, LogManager.DEBUG_MESSAGE_LEVEL ); if( status != 0 ){ throw new RuntimeException("Pegasus was unable to update the the worflow database file found at" + " ~/.pegasus/workflow.db . If this file is corrupted, a solution for" + " problem is to remove the file with the command: rm -f ~/.pegasus/workflow.db " + " - but note that doing so will remove old workflows from the Pegasus Dashboard."); } } catch(IOException ioe){ mLogger.log("IOException while executing " + basename, ioe, LogManager.ERROR_MESSAGE_LEVEL); throw new RuntimeException( "IOException while executing " + command , ioe ); } catch( InterruptedException ie){ //ignore } return true; } }