def BuildConfiguration(configName): DefineDatabase = simsubs.DefineDatabase() machineEntry = simenv.LocalMachineEntry req_keys = ['user', 'email', 'make'] simlib.VerifyKeys(machineEntry, req_keys) user = machineEntry.GetKey("user") email = machineEntry.GetKey("email") DefineDatabase.Set('USER', user) DefineDatabase.Set('EMAIL', email) make = DefineDatabase.SubAll(machineEntry.GetKey('make')) display("Building %s" % configName) ret = simlib.ExecuteCommand("cd %s && %s %s 2>&1" % (simenv.CACTUS_PATH, make, configName)) if ret != 0: sys.exit(1) display("Building utilities for %s" % configName) ret = simlib.ExecuteCommand("cd %s && %s %s-utils 2>&1" % (simenv.CACTUS_PATH, make, configName)) if ret != 0: sys.exit(1)
def command_build(): DefineDatabase = simsubs.DefineDatabase() configList = simenv.OptionsManager.args if len(configList) == 0: configList = [simlib.GetDefaultConfiguration()] for config in configList: display("Using configuration: %s" % config) machineEntry = simenv.LocalMachineEntry req_keys = ['user', 'email'] simlib.VerifyKeys(machineEntry, req_keys) user = machineEntry.GetKey("user") email = machineEntry.GetKey("email") DefineDatabase.Set('USER', user) DefineDatabase.Set('EMAIL', email) cactusDir = simenv.CACTUS_PATH info("Cactus Directory: %s" % cactusDir) for config in configList: PrepConfiguration(config) if not simenv.OptionsManager.GetOption('virtual'): BuildConfiguration(config) else: BuildVirtual(config) display("Done.")
def init(self, machineName): self.localMachineName = simenv.LocalMachine self.localMachineEntry = simenv.LocalMachineEntry if self.localMachineEntry == None: fatal("unknown local machine %s" % self.localMachineName) self.machineName = machineName if self.machineName == self.localMachineName: fatal("remote machine %s is the same as local machine %s" % (self.machineName, self.localMachineName)) self.machineEntry = simenv.ConfigurationDatabase.GetMachine( self.machineName) if self.machineEntry == None: fatal("unknown remote machine %s" % self.machineName) req_keys = ['envsetup', 'sourcebasedir', 'user', 'hostname'] simlib.VerifyKeys(self.localMachineEntry, req_keys) self.localEnvSetup = self.localMachineEntry.GetKey("envsetup") DefineDatabase = simsubs.DefineDatabase() DefineDatabase.Set("USER", simenv.LocalMachineEntry.user) self.localEnvSetup = DefineDatabase.SubAll(self.localEnvSetup)
def listSimulations(self): machineEntry = simenv.LocalMachineEntry simlib.VerifyKeys(machineEntry, ['archivebasepath']) basepath = machineEntry.GetKey('archivebasepath') return self.GetStoredSimulations(basepath)
def __init__(self, simArchive): self.SimArchive = simArchive machineEntry = simenv.LocalMachineEntry simlib.VerifyKeys(machineEntry, ['archivetoolspath']) self.ToolsPath = machineEntry.archivetoolspath if not (os.path.exists(self.ToolsPath)): dprint("Error: could not access archive tools path %s" % self.ToolsPath) sys.exit(1)
def authenticate(self): machineEntry = simenv.LocalMachineEntry simlib.VerifyKeys(machineEntry, ['archiveuser']) username = machineEntry.GetKey('archiveuser') ret = self.Driver.authenticate(username) if ret != 0: dprint( "Error: could not authenticate for archiving using driver %s" % self.DriverName) sys.exit(1) else: dprint("Authentication for archiveuser %s successful" % username)
def get(self, simulationid, dstPath, restartid=None): machineEntry = simenv.LocalMachineEntry simlib.VerifyKeys(machineEntry, ['archivebasepath']) basepath = machineEntry.GetKey('archivebasepath') srcPath = "%s/%s" % (machineEntry.GetKey('archivebasepath'), simulationid) if restartid != None: if len(restartid) == 4: srcPath = "%s/output-%s" % (dstPath, restartid) else: srcPath = "%s/output-%04d" % (dstPath, int(restartid)) dprint("Archive source path: %s" % srcPath) dprint("Archive destination path: %s" % dstPath) self.Driver.get(srcPath, dstPath)
def GetExecHost(restart): DefineDatabase = simsubs.DefineDatabase() (machine, machineEntry, sourceBaseDir) = simlib.GetLocalEnvironment() job_id = restart.GetJobId() job_status = 'U' if job_id != -1: job_status = GetJobStatus(job_id) if job_status != 'R': warning("Job is not running, cannot retreive exechost") return None simlib.VerifyKeys(machineEntry, ['exechost', 'exechostpattern']) DefineDatabase.Set('JOB_ID', job_id) DefineDatabase.Set('USER', machineEntry.user) DefineDatabase.Set('SIMULATION_NAME', restart.SimulationName) exechost = DefineDatabase.SubAll(machineEntry.GetKey('exechost')) exechostpattern = DefineDatabase.SubAll( machineEntry.GetKey('exechostpattern')) output, rc = simlib.ExecuteCommand(exechost, True) rx = re.compile(exechostpattern, re.MULTILINE) matches = rx.search(output) if rc or matches == None: warning("Unable to retrieve exechost using pattern %s" % exechostpattern) return None return matches.group(1)
def list_archived_simulations(): simlib.RequireMachine() machineEntry = simenv.LocalMachineEntry simlib.VerifyKeys(machineEntry, ['archivetype']) archiveType = machineEntry.archivetype ArchiveEngine = simarchive.SimArchive(archiveType) ArchiveEngine.authenticate() simulations = ArchiveEngine.listSimulations() if simenv.OptionsManager.GetOption('name-only'): for sim in simulations: print sim return for sim in simulations: display("") display("%s: " % sim['SimulationId']) display(" Archive Path: %s" % sim['StoredPath']) display(" Simulation Name: %s" % sim['SimulationName']) display(" Machine: %s" % sim['Machine']) display(" Hostname: %s" % sim['Hostname']) display(" User: %s" % sim['User']) display(" Date: %s" % sim['Date']) restarts = sim['Restarts'] display(" Restarts: found %s restart(s)" % len(restarts)) for r in restarts: display(" %s" % r)
def store(self): if self.Restart == None: dprint("Error: Cannot store null simulation") sys.exit(1) machineEntry = simenv.LocalMachineEntry metadataFile = self.buildMetadataFile() simlib.VerifyKeys(machineEntry, ['archivebasepath']) dstPath = "%s/%s" % (machineEntry.GetKey('archivebasepath'), self.Restart.Properties.simulationid) if self.Restart.RestartID == -1: srcPath = self.Restart.SimulationDir else: srcPath = self.Restart.RestartDir dstPath = "%s/output-%s" % (dstPath, self.Restart.LongRestartID) dprint("Archive source path: %s" % srcPath) dprint("Archive destination path: %s" % dstPath) self.Driver.store(srcPath, dstPath)
def PrepConfiguration(configName): DefineDatabase = simsubs.DefineDatabase() machineEntry = simenv.LocalMachineEntry req_keys = ['user', 'email', 'make'] simlib.VerifyKeys(machineEntry, req_keys) user = machineEntry.GetKey("user") email = machineEntry.GetKey("email") DefineDatabase.Set('USER', user) DefineDatabase.Set('EMAIL', email) make = DefineDatabase.SubAll(machineEntry.GetKey('make')) subfolders = ['bindings', 'build', 'config-data', 'lib', 'scratch'] configBase = simlib.BuildPath(simenv.CONFIGS_PATH, configName) propertiesFile = simlib.BuildPath(configBase, "properties.ini") if not os.path.exists(configBase): try: os.mkdir(configBase) except OSError: pass #simlib.ExecuteCommand("mkdir %s" % configBase) for sub in subfolders: sf = simlib.BuildPath(configBase, sub) simlib.ExecuteCommand("mkdir %s" % sf) else: # The config dir exists already if not os.path.exists(propertiesFile): fatal( "Configuration %s has no properties.ini file. Either this is not a SimFactory configuration, or the configuration has become corrupted. If you think the configuration has been corrupted, you will need to delete it and run the sim build command again." % (configName)) prop = simproperties.SimProperties() prop.init(propertiesFile) build_reconfig = GetConfigValue(prop, "reconfig") build_clean = GetConfigValue(prop, "clean") build_debug = GetConfigValue(prop, "debug") build_optimise = GetConfigValue(prop, "optimise") build_unsafe = GetConfigValue(prop, "unsafe") build_profile = GetConfigValue(prop, "profile") if build_debug: display("Disabling optimisation because debug was selected") build_optimise = False # update our properties.ini prop.RemoveProperty("reconfig") prop.RemoveProperty("clean") prop.AddProperty("debug", build_debug) prop.AddProperty("optimise", build_optimise) prop.AddProperty("unsafe", build_unsafe) prop.AddProperty("profile", build_profile) # Remove the executable, so that it is not accidentally used # while it is rebuilt. Do this before the configuration is # modified in any way, but only after some basic error # checking. try: os.remove("exe/cactus_%s" % configName) except OSError: pass try: shutil.rmtree("exe/%s" % configName, ignore_errors=True) except OSError: pass prop.Save() storedOptions = simlib.BuildPath(configBase, "OptionList") hasStoredOptions = os.path.exists(storedOptions) cctkConfigPath = simlib.BuildPath(configBase, "config-data", "cctk_Config.h") hasCompleteConfig = os.path.exists(cctkConfigPath) if hasStoredOptions: storedOptionSettings = simlib.GetFileContents(storedOptions) else: storedOptionSettings = None info("HasStoredOptions: %s" % hasStoredOptions) removeConfig = False # default behaviour # we are only updating the OptionList if its explicitly specified with --optionlist, really. if hasStoredOptions and not simenv.OptionsManager.RawOptionDefined( "optionlist"): info("Use stored options list: %s" % storedOptions) optionlist = storedOptions else: optionlist = simlib.GetOptionList(False) info("optionlist is: %s" % optionlist) if optionlist == None or not os.path.exists(optionlist): display("Warning: no option list specified, using blank option list") optionSettings = str() else: optionSettings = simlib.GetFileContents(optionlist) DefineDatabase.AddReplacement("DEBUG", simlib.BoolToYesNo(build_debug)) DefineDatabase.AddReplacement("OPTIMISE", simlib.BoolToYesNo(build_optimise)) DefineDatabase.AddReplacement("UNSAFE", simlib.BoolToYesNo(build_unsafe)) DefineDatabase.AddReplacement("PROFILE", simlib.BoolToYesNo(build_profile)) # add support for CACHELINE_BYTES and CACHE_SIZE CACHELINE_BYTES = simenv.LocalMachineEntry.GetKey("L3linesize") if CACHELINE_BYTES != None: DefineDatabase.AddReplacement("CACHELINE_BYTES", CACHELINE_BYTES) CACHE_SIZE = simenv.LocalMachineEntry.GetKey("L3size") if CACHE_SIZE != None: DefineDatabase.AddReplacement("CACHE_SIZE", CACHE_SIZE) optionSettings = DefineDatabase.SubAll(optionSettings) hasOutdatedConfig = (not hasCompleteConfig) or ( storedOptionSettings == None) or (storedOptionSettings != optionSettings) if hasOutdatedConfig: info("hasCompleteConfig: %s" % hasCompleteConfig) info("hasOutdatedConfig: %s" % hasOutdatedConfig) info("build_reconfig: %s" % build_reconfig) # if build virtual, disable configging. if hasOutdatedConfig or build_reconfig: if storedOptionSettings != None: oldVersion = simlib.GetVersion(storedOptionSettings) else: oldVersion = "" newVersion = simlib.GetVersion(optionSettings) info("oldVersion %s, newVersion %s" % (oldVersion, newVersion)) removeConfig = removeConfig or newVersion != oldVersion display("Reconfiguring %s" % configName) simlib.RemoveFile("%s.old" % storedOptions) simlib.RenameFile(storedOptions, "%s.old" % storedOptions) # TODO: Write new option list only after the make *-realclean below! display("Writing configuration to: %s" % storedOptions) simlib.WriteContents(storedOptions, optionSettings) #"echo yes | { $make $configuration_name-config options=configs/$configuration_name/OptionList; }"; if not simenv.OptionsManager.GetOption('virtual'): cmd = "cd %s && echo yes | { %s %s-config options=%s; } 2>&1" % ( simenv.CACTUS_PATH, make, configName, storedOptions) ret = simlib.ExecuteCommand(cmd) if ret != 0: sys.exit(1) #force a rebuild simlib.RemoveFile( simlib.BuildPath(configBase, 'config-data', 'make.thornlist')) #remove the old config if necessary if removeConfig: display("Complete rebuild required") else: if not hasStoredOptions: fatal( "Configuration %s has no option list, and no option list was specified." % configName) if not simenv.OptionsManager.GetOption('virtual'): info("build_clean: %s" % build_clean) info("removeConfig: %s" % removeConfig) if build_clean or removeConfig: display("Cleaning %s" % configName) ret = simlib.ExecuteCommand("cd %s && %s %s-realclean 2>&1" % (simenv.CACTUS_PATH, make, configName)) if ret != 0: sys.exit(1) ## deal with submit script now storedSubmitScript = simlib.BuildPath(configBase, "SubmitScript") hasStoredSubmitScript = os.path.exists(storedSubmitScript) if simenv.OptionsManager.GetOption('no-submitscript'): if hasStoredSubmitScript: display("Removing stored submit script for configuration %s" % configName) os.unlink(storedSubmitScript) warning("empty submit script will disable submission") else: # the submit script is entirely optional. no submit script # just means submission is disabled. submitscript = simlib.GetSubmitScript() info("SubmitScript is: %s" % submitscript) if submitscript != None: sContents = simlib.GetFileContents(submitscript) ssContents = simlib.GetFileContents(storedSubmitScript) submitScriptOutdated = not hasStoredSubmitScript or simenv.OptionsManager.RawOptionDefined( "submitscript") if sContents != ssContents: warning("default submit script contents have changed") if (submitScriptOutdated or build_reconfig): display("Updated script file for configuration %s" % configName) simlib.RemoveFile("%s.old" % storedSubmitScript) simlib.RenameFile(storedSubmitScript, "%s.old" % storedSubmitScript) shutil.copy(submitscript, storedSubmitScript) else: if not hasStoredSubmitScript: warning("empty submit script will disable submission") ## deal with run script now storedRunScript = simlib.BuildPath(configBase, "RunScript") hasStoredRunScript = os.path.exists(storedRunScript) runscript = simlib.GetRunScript(False) info("RunScript is: %s" % runscript) if runscript != None: sContents = simlib.GetFileContents(runscript) ssContents = simlib.GetFileContents(storedRunScript) runScriptOutdated = not hasStoredRunScript or simenv.OptionsManager.RawOptionDefined( "runscript") if sContents != ssContents: warning("default run script contents have changed") if (runScriptOutdated or build_reconfig): display("Updated runscript file for configuration %s" % configName) simlib.RemoveFile("%s.old" % storedRunScript) simlib.RenameFile(storedRunScript, "%s.old" % storedRunScript) shutil.copy(runscript, storedRunScript) else: if not hasStoredRunScript: fatal( "Configuration %s has no run script, and no run script file was specified" % configName) ## deal with thorn list now storedThornList = simlib.BuildPath(configBase, "ThornList") hasStoredThornList = os.path.exists(storedThornList) needThornList = not hasStoredThornList thornlist = simlib.GetThornList(needThornList) info("ThornList is: %s" % thornlist) if thornlist != None: tContents = simlib.GetThornListContents(thornlist) ttContents = simlib.GetFileContents(storedThornList) thornListOutdated = not hasStoredThornList or simenv.OptionsManager.RawOptionDefined( "thornlist") if tContents != ttContents: warning("default thorn list contents have changed") if (thornListOutdated or build_reconfig): display("Updated thorn list for configuration %s" % configName) simlib.RemoveFile("%s.old" % storedThornList) simlib.RenameFile(storedThornList, "%s.old" % storedThornList) simlib.WriteContents(storedThornList, tContents) else: if not hasStoredThornList: fatal( "Configuration %s has no thorn list, and no thorn list file was specified" % configName)
def CompileCommand(machineName, rsyncInfo, paths, oldRsync=False): global localMachineName global localMachineEntry global local_sourcebasedir global local_suffix DefineDatabase = simsubs.DefineDatabase() (rsynccmd, rsyncopts) = rsyncInfo rsyncversion = simlib.RsyncVersion(rsyncInfo) if machineName == localMachineName: fatal("cannot sync to local machine") machineEntry = simenv.ConfigurationDatabase.GetMachine(machineName) # get our IO machine -- if iomachine doesn't exist, it returns itself. ioMachine = simlib.GetIOMachine(machineName) if ioMachine != machineName: machineEntry = simenv.ConfigurationDatabase.GetMachine(ioMachine) machineName = ioMachine # make sure we have all the info we need. mreq_keys = [ 'user', 'sourcebasedir', 'hostname', 'rsynccmd', 'rsyncopts', 'sshcmd', 'sshopts' ] simlib.VerifyKeys(machineEntry, mreq_keys) DefineDatabase.Set('USER', machineEntry.user) sourcebasedir = DefineDatabase.SubAll(machineEntry.sourcebasedir) # There need to be two define databases, one for the local and # another for the remote system. Currently, USER is for the # remote and SOURCEDIR is for the local system -- this is # inconsistent. #local_sourcebasedir = DefineDatabase.SubAll(localMachineEntry.sourcebasedir) source_name = local_suffix #source_name = simlib.GetDirSuffix(local_sourcebasedir) local_sourcedir = simlib.BuildPath(local_sourcebasedir, source_name) DefineDatabase.Set('SOURCEDIR', local_sourcedir) localsshsetup = DefineDatabase.SubAll(machineEntry.localsshsetup) # sshcmd = machineEntry.sshcmd # sshopts = machineEntry.sshopts # sshcmd = "%s %s" % (sshcmd, sshopts) # trampoline = simlib.GetTrampoline(ioMachine) # if trampoline: # tentry = simenv.ConfigurationDatabase.GetMachine(trampoline) # trampoline_sourcebasedir = simlib.GetSourceBaseDir(tentry) # trampoline_sourcedir = os.path.join(trampoline_sourcebasedir, source_name) # DefineDatabase.Set('SOURCEDIR', trampoline_sourcedir) # sshcmd = DefineDatabase.SubAll(sshcmd) # DefineDatabase.Set('SOURCEDIR', local_sourcedir) # sshcmd = simlib.GetSSHCommand(trampoline, sshcmd) # sshcmd = DefineDatabase.SubAll(sshcmd) sshcmd = simlib.GetSSHCommand(localMachineName, ioMachine, None) # If there is more than one explicit path given only accept # top-level directories This could be extended to do the right # thing when multiple explicit paths are given but would require # running rsync multiple times rsyncfiles = [] if len(paths) == 1: rsyncfiles = paths [head, tail] = os.path.split(rsyncfiles[0]) local_suffix = os.path.join(local_suffix, head) else: for file in paths: if file == '': continue [head, tail] = os.path.split(file) if head != "": fatal( "Only top level paths may be specified when syncing multiple paths but '%s' given." % file) elif not os.path.exists(tail): warning("Specified sync path '%s' not found." % tail) else: rsyncfiles.append(tail) # Note: # - We omit --times, since the target system should recompile when # a file changed there # - We omit --group and --owner, since this probably works for # root only, and all files on the targe system should rather # belong to the user # - We omit -D, since we don't expect to have devices or other # special files # - Since we omit --times, we add --checksum so that differing # modification times don't lead to a retransmission # - NOTE: rsync before 3.0.8 has an error that makes --checksum # unreliable under certain circumstances (see # <https://rsync.samba.org/ftp/rsync/src/rsync-3.0.8-NEWS>). We # cannot use --ignore-times instead because this modifies all # files' timestamps (and is also very expensive). rsyncoptions = [ '--checksum', '--compress', '--delete', '--hard-links', '--links', '--partial', '--perms', '--progress', '--recursive', '--sparse', '--stats', #'--times', '--verbose' ] # We need to use a different rules file for pre 3.0.0 versions of rsync ruleFile = 'filter.rules' if rsyncversion[0] < 3 or oldRsync: info( 'Old rsync version in use (local version is %s.%s.%s). Upgrade to at least 3.0.0 both locally and remotely for best performance.' % rsyncversion) ruleFile = 'filter.prersync3.rules' userRuleFile = "%s/etc/%s" % (simenv.BASE_PATH, "filter.local.rules") if os.path.exists(userRuleFile): rsyncoptions.append("--filter 'merge %s'" % (userRuleFile)) rsyncoptions.append("--filter 'merge %s/etc/%s'" % (simenv.BASE_PATH, ruleFile)) fullpath = "%s@%s:%s%s%s" % (machineEntry.user, machineEntry.hostname, sourcebasedir, os.sep, local_suffix) arguments = " ".join(simlib.GetArguments()) cmd = "%s --rsh=%s --rsync-path=%s %s %s %s" % ( rsynccmd, simlib.QuoteSafe(sshcmd), simlib.QuoteSafe(machineEntry.rsynccmd), rsyncopts, machineEntry.rsyncopts, arguments) cmd = "%s %s" % (cmd, " ".join(rsyncoptions)) cmd = "%s %s" % (cmd, " ".join(rsyncfiles)) cmd = "%s %s" % (cmd, fullpath) mkdirpath = os.path.join(sourcebasedir, local_suffix) mkdircmd = "mkdir -p %s" % simlib.QuoteSafe(mkdirpath) #mkdircmd = "%s %s@%s %s" % (sshcmd, machineEntry.user, machineEntry.hostname, simlib.QuoteSafe(mkdircmd)) mkdircmd = simlib.GetSSHCommand(localMachineName, ioMachine, mkdircmd) cmd = "cd %s && { %s; } && { %s || { %s && %s; } }" % ( simlib.QuoteSafe(local_sourcedir), localsshsetup, cmd, mkdircmd, cmd) return cmd
def GetJobStatus(job_id): # TODO: there needs to be documentation stating what the possible # return values are DefineDatabase = simsubs.DefineDatabase() (machine, machineEntry, sourceBaseDir) = simlib.GetLocalEnvironment() simlib.VerifyKeys(machineEntry, [ 'getstatus', 'queuedpattern', 'runningpattern', 'statuspattern', 'user' ]) status_command = machineEntry.GetKey('getstatus') status_pattern = machineEntry.GetKey('statuspattern') queued_pattern = machineEntry.GetKey('queuedpattern') running_pattern = machineEntry.GetKey('runningpattern') holding_pattern = machineEntry.GetKey('holdingpattern') user = machineEntry.GetKey('user') DefineDatabase.Set('USER', user) DefineDatabase.Set('JOB_ID', job_id) status_command = DefineDatabase.SubAll(status_command) status_pattern = DefineDatabase.SubAll(status_pattern) queued_pattern = DefineDatabase.SubAll(queued_pattern) running_pattern = DefineDatabase.SubAll(running_pattern) holding_pattern = DefineDatabase.SubAll(holding_pattern) #capture output. output, ret = simlib.ExecuteCommand(status_command, output=True) # U == unknown? status = 'U' if ret != None: lines = output.split("\n") #first, lets see if the job is still in the queue, regardless of whether or not we can determine the job status # TODO: counting lines doesn't help detecting errors InQueue = lines.count(job_id) > 0 matched = [] for line in lines: matches = re.search(status_pattern, line) if matches != None: # queued_pattern if re.search(queued_pattern, line): status = 'Q' matched.append(queued_pattern) # running_pattern if re.search(running_pattern, line): status = 'R' matched.append(running_pattern) # holding_pattern if holding_pattern != None: if re.search(holding_pattern, line): status = 'H' matched.append(holding_pattern) # TODO: matches is set in the last loop iteration only; this if # statement is bogus if matches > 1: # TODO: output a better error message; the list of patterns # alone is not useful because patterns are difficult to read; # better would be also what state the patterns are for fatal("multiple status patterns matched: %s" % matched) if InQueue and status == 'U': status = 'E' if status == 'U': warning("job status is U") dprint("queue status return code is: %d" % ret) dprint("queue status output is:") for line in lines: dprint(" lines=[%s]" % line) dprint("patterns are:") dprint(" status_pattern=[%s]" % status_pattern) dprint(" queued_pattern=[%s]" % queued_pattern) dprint(" running_pattern=[%s]" % running_pattern) dprint(" holding_pattern=[%s]" % holding_pattern) return status