def mirror_remote(src_dir): # # This isn't invoked as a top-level operation so don't create a full # logfile; just use standard debugging-level support. # logger = enbackup.log.Logger('mirror') try: config = enbackup.utils.DefaultConfigParser( { "Paths" : { "src_dir_restrict": src_dir_restrict_default } }) config.read(cfg_file_path) src_dir_restrict = config.get("Paths", "src_dir_restrict") (path_is_valid, msg) = validate_local_dir(src_dir, src_dir_restrict) if not path_is_valid: logger.log(msg) raise MirrorCmdError(src_dir, msg) # # If all is well, start the rsync server to mirror the requested # directory. If currently running as root, make sure we drop down to # the enbackup user account for actually running the rsync. We don't # really expect this to happen on the remote end, but best to be # sure! # rsync_cmd_str = mirror_cmd_remote + "{0}".format(src_dir) if os.geteuid() == 0: rsync_cmd = ["su", get_username(), "--command", rsync_cmd_str] else: rsync_cmd = rsync_cmd_str.split() logger.debug("Remote mirror command: {0}".format(rsync_cmd)) logger.debug("About to lock '{0}' for remote mirror". format(src_dir)) with DirLock("mirror-remote (PID {0})".format(os.getpid()), src_dir): run_cmd(rsync_cmd, logger) logger.debug("Remote mirror done") except Exception as e: logger.error("Failed remote mirror: {}".format(e)) raise
def notify_remote(server, remote_subcommand): ssh_user = get_username() # # Verify that the 'server' argument is a simple name -- no spaces, # escaping, quotes, etc. permitted -- before running the command. # If running as root, switch to the enbackup user before running # the SSH so that the right key gets picked up. In future we # could make this configurable... # if re.match("([A-Za-z0-9/\-_:]+)", server): ssh_cmd_str = "ssh {0}@{1} enbackup notify {2}".format( ssh_user, server, " ".join(remote_subcommand)) if os.geteuid() == 0: ssh_cmd = ["su", ssh_user, "--command", ssh_cmd_str] else: ssh_cmd = ssh_cmd_str.split() run_cmd(ssh_cmd, logger) else: logger.error("Server '{0}' name is not in the correct format".format( server))
def mirror_local(src, tgt_dir): # # Start recording details of this operation to a logfile: # logger = start_logger() try: config = enbackup.utils.DefaultConfigParser( { "Paths" : { "tgt_dir_restrict": tgt_dir_restrict_default }, "Logging" : { "log_email": email_default, "log_filter": "" }}) config.read(cfg_file_path) tgt_dir_restrict = config.get("Paths", "tgt_dir_restrict") email_to = config.get("Logging", "log_email") log_filter_file = config.get("Logging", "log_filter") # # Check the target directory is valid on this server. # (path_is_valid, msg) = validate_local_dir(tgt_dir, tgt_dir_restrict) if not path_is_valid: logger.log(msg) raise MirrorCmdError(tgt_dir, msg) # # Get the source directory. This is selected from the config file, # based on the incoming argument, so we trust it's a sane value: # try: src_server = config.get(src, "src_server") src_dir = config.get(src, "src_dir") except ConfigParser.NoSectionError: logger.log("No source entry found in %s matching keyword '%s'" % (cfg_file_path, src)) raise # # Work out which directory we're going to be writing to so we can # lock it. The target directory depends on the format of the # source directory passed to rsync: # - If the source ends in a '/' then the contents are mirrored; # the target is just the target dir as passed by the caller. # - If the source does not end in a '/' then everything will # be copied into a subdirectory -- we should append the source # directory name to the passed target directory to get the # path to lock. # # This behavior falls out nicely if we just use the 'basename' # function to extract the last element of the source directory: # lock_dir = os.path.join(tgt_dir, os.path.basename(src_dir)) # # If all is well, spawn rsync to mirror the data across. # Any failures will result in an exception which will # get propagated up to the caller. If currently running as root, # make sure we drop down to the enbackup user account for actually # running the rsync (we don't want to open any remote connections # as root). # if src_server != "": src = "{0}:{1}".format(src_server, src_dir) else: src = src_dir rsync_cmd_str = mirror_cmd_local + "{0} {1}".format(src, tgt_dir) if os.geteuid() == 0: rsync_cmd = ["su", get_username(), "--command", rsync_cmd_str] else: rsync_cmd = rsync_cmd_str.split() logger.debug("Local mirror command: {0}".format(rsync_cmd)) logger.debug("About to lock '{0}' for local mirror".format(lock_dir)) start_time = datetime.datetime.now() with DirLock("mirror-local (PID: {0})".format(os.getpid()), lock_dir): (rc, output, err) = run_cmd_output(rsync_cmd, logger) logger.debug("Local mirror done") duration = datetime.datetime.now() - start_time # # Filter the results of the rsync to remove noise, then record them # in a log file, and send an email with the details. # if log_filter_file != "": log_filter = StringFilter(log_filter_file) filtered_output = log_filter.filter(output.split("\n"), True) filtered_output = "\n".join(filtered_output) else: filtered_output = output if rc == 0: subject = "Mirror {0} completed".format(src) result_msg = \ "Mirroring has completed successfully!\n" \ " from: {0}\n" \ " to: {1}\n" \ "Total elapsed time: {2}\n\n" \ "############ rsync summary log ############\n\n" \ "{3}".format(src, tgt_dir, duration, filtered_output) else: subject = "Mirror {0} FAILED".format(src) result_msg = \ "Mirroring of {0} to {1} FAILED (code {2}), please investigate." \ "\n\n{3}\n\n{4}".format(src, tgt_dir, rc, filtered_output, err) logger.log(result_msg) logger.send_email(subject, result_msg, email_to) except Exception as e: logger.error("Failed local mirror: {}".format(e)) raise