# sim-sync -- sync source trees across machines using information from the machine database # # Michael Thomas # Center for Computation & Technology # Louisiana State University # import sys, os optionGroups = ['sim-sync'] Purpose = "sync cactus sourcetree to a remote machine" ############################################ import simenv,simsubs,simlib from libutil import * known_commands = [] usage_strings = {'sync': 'sync cactus sourcetree to a remote machine'} global local_suffix global local_sourcebasedir global localMachineName global localMachineEntry local_suffix = None local_sourcebasedir = None localMachineName = None localMachineEntry = None ############################### FUNCTIONS ############################### def GetRsyncInfo(machineEntry): return GetSubbedInfo(machineEntry, ['rsynccmd', 'rsyncopts']) def GetSSHInfo(machineEntry): return GetSubbedInfo(machineEntry, ['sshcmd', 'sshopts']) def GetSubbedInfo(machineEntry, keys): DefineDatabase = simsubs.DefineDatabase() data = list() for k in keys: d = DefineDatabase.SubAll(machineEntry.GetKey(k)) data.append(d) return data def CompileCommand(machineName, rsyncInfo): global localMachineName global localMachineEntry global local_sourcebasedir global local_suffix DefineDatabase = simsubs.DefineDatabase() # mode of operation sync_parfiles = simenv.OptionsManager.GetOption('sync-parfiles') sync_sourcetree = simenv.OptionsManager.GetOption('sync-sourcetree') (rsynccmd, rsyncopts) = 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 sourcebasedir = machineEntry.sourcebasedir 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) rsyncfiles = [] rsyncoptions = ['--archive', '--hard-links', '--sparse', '--verbose', '--progress', '--partial', '--stats', '--compress', '--delete', '--delete-excluded'] # sync source tree if sync_sourcetree: sources = simenv.ConfigurationDatabase.GetConfigOption('sync-sources') #dprint("sync-sources is: %s " % sources) if type(sources) == list: for r in sources: rp = simlib.BuildPath(local_sourcedir, r) #display("checking if %s exists" % rp) if os.path.exists(rp): rsyncfiles.append(r) # sync par files if sync_parfiles: sources = simenv.ConfigurationDatabase.GetConfigOption('sync-parfiles') #dprint("sync-parfiles is: %s " % sources) if type(sources) == list: for r in sources: rp = simlib.BuildPath(local_sourcedir, r) #display("checking if %s exists" % rp) if os.path.exists(rp): rsyncfiles.append(r) # build excludes sources = simenv.ConfigurationDatabase.GetConfigOption('sync-excludes') if type(sources) == list: for r in sources: r = r.strip() if len(r) > 0: rsyncoptions.append("--exclude '%s'" % r) 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) mkdirssh = "%s@%s" % (machineEntry.user, machineEntry.hostname) mkdirpath = "%s%s%s" % (sourcebasedir, os.sep, local_suffix) mkdircmd = "%s %s mkdir -p %s" % (sshcmd, mkdirssh, mkdirpath) cmd = "cd '%s' && { %s; } && %s && %s" % (local_sourcedir, localsshsetup, mkdircmd, cmd) return cmd ############################### MAIN ############################### def main(): ## HEADER ## simlib.RequireMachine() simenv.ConfigurationDatabase.RequireCapability("access") global local_suffix global local_sourcebasedir global localMachineName global localMachineEntry machineList = simenv.OptionsManager.args if len(machineList) == 0: fatal("Error: no machines specified") if simenv.OptionsManager.args[0] == 'sync': simenv.OptionsManager.args.pop(0) info("using machines: %s\n" % machineList) info("current working directory: %s\n" % os.getcwd()) if simenv.CACTUS_PATH == None: fatal("cannot proceed with an unknown CACTUS_PATH") cactusDir = simenv.CACTUS_PATH display("Cactus Directory: %s" % cactusDir) # mode of operation sync_parfiles = simenv.OptionsManager.GetOption('sync-parfiles') sync_sourcetree = simenv.OptionsManager.GetOption('sync-sourcetree') if not(sync_parfiles or sync_sourcetree): fatal("neither sync-parfiles or sync-sourcetree was specified. should never happen") info("Enabled Options:") info("sync-parfiles: %s" % sync_parfiles) info("sync-sourcetree: %s" % sync_sourcetree) print # get our local_sourcebasedir local_sourcebasedir = simlib.GetLocalSourceBaseDir() local_suffix = simenv.CACTUS_PATH.replace("%s/" % local_sourcebasedir, "") info("CACTUS_PATH: %s" % simenv.CACTUS_PATH) info("local_sourcebasedir: %s" % local_sourcebasedir) info("local_suffix: %s" % local_suffix) localMachineName = simenv.LocalMachine localMachineEntry = simenv.LocalMachineEntry # returns list (rsynccmd, rsyncopts) rsyncInfo = GetRsyncInfo(localMachineEntry) errors = 0 for m in machineList: cmd = CompileCommand(m, rsyncInfo) ret = simlib.ExecuteCommand(cmd) if ret != 0: errors = errors + 1 display("\nError while syncing to %s." % m) if errors == 0: display("\nSync complete.") else: display("\nErrors occurred during synchronisation.")