def get_schedule_command(self, profile, type): # Configures the backup and log target paths log_path = profile.backup_directory filename = "\$BACKUP_NAME" if type == "incremental": filename = "inc/\$BACKUP_NAME" log_path = joinpath(log_path, 'inc') log_path = joinpath(log_path, "\$BACKUP_NAME.log 2>&1") # Creates the mysqlbackup command call command = self.create_backup_command_call(profile, type, to_schedule=True, filename=filename) # Chooses the proper scheduling data and creates the schedule command schedule_data = profile.full_backups if type == 'full' else profile.inc_backups schedule = [] schedule.append(str(schedule_data.minute)) schedule.append('*' if schedule_data.frequency == Frequency.hourly else str(schedule_data.hour)) schedule.append('*' if schedule_data.frequency in [Frequency.hourly,Frequency.daily,Frequency.weekly] else str(schedule_data.month_day)) schedule.append('*') schedule.append('*' if schedule_data.frequency != Frequency.weekly else str(schedule_data.week_day)) schedule.append("BACKUP_NAME=\$(date +\%Y-\%m-\%d_\%H-\%M-\%S); " + command) schedule.append("> " + log_path) # A temporary file to store the crontab cron_file = "%s/wb_cron_file" % profile.backup_directory cron_entry = " ".join(schedule) schedule_command = 'crontab -l > %s; echo "%s" >> %s; crontab %s; rm %s' % (cron_file, cron_entry, cron_file, cron_file, cron_file) return schedule_command
def create_backup_command_call(self, profile, type, to_schedule, filename=None): cmd_data = [] if ' ' in self._context.config.backup_command: cmd_data.append('"%s"' % self._context.config.backup_command) else: cmd_data.append('%s' % self._context.config.backup_command) # Uses the configuration file for the backup (MUST be the 1st option) cmd_data.append('--defaults-file=%s' % profile.defaults_file) # If a filename is explicitly requested, then use it if filename: if type == 'incremental': #cmd_data.append('--backup-dir=%s' % joinpath(profile.backup_directory, filename)) cmd_data.append('--incremental-backup-dir=%s' % joinpath(profile.backup_directory, filename)) else: cmd_data.append('--backup-dir=%s' % joinpath(profile.backup_directory, filename)) # Passes the mutually excluyent parameters if type == 'full': # The compress option is set only for full backups when apply-log is not # enabled, this is because --compress will be ignored anyway if profile.compress and not profile.apply_log: cmd_data.append('--compress') elif type == 'incremental': cmd_data.append('--incremental') # apply-log is only used on full backups when enabled if profile.apply_log and type == 'full': cmd_data.append('backup-and-apply-log') else: cmd_data.append('backup') return " ".join(cmd_data)
def save_changes(self): if self.validate(): path = self._dest_directory.get_string_value() if not self._context.ctrl_be.server_helper.file_exists(path): r = mforms.Utilities.show_warning("Save Backup Profile", "Target backup directory '%s' does not exist, would you like to create it?" % path, "Create", "Cancel", "") if r == mforms.ResultOk: self._context.server_interface.create_directory(path) else: return self.flush_data() # The next operations ONLY apply if anything changed on the profile if self._profile.has_changed: self._profile.save() path = joinpath(path, "inc") if not self._context.ctrl_be.server_helper.file_exists(path): self._context.server_interface.create_directory(path) # Reschedules the backup with the new information self._context.server_interface.unschedule_backup(self._profile) self._context.server_interface.schedule_backup(self._profile) if self.profile_saved_callback is not None: self.profile_saved_callback(self._profile) self._owner.hide_editor()
def restore_backup(self, backup_entry, output_handler=None): # create a defaults file containing the cnf data saved by mysqlbackup in backup-my.cnf and # the last known correct datadir import uuid restore_defaults_file = joinpath(self._context.config.backup_home, str(uuid.uuid1())+"-restore.cnf") data = self.get_file_content(joinpath(backup_entry.data_path, "backup-my.cnf")) data += "datadir = %s\n" % self._context.config.datadir self.perform_as_user(self._context.mysql_user, lambda as_user, user_password: self._context.ctrl_be.server_helper.set_file_content(restore_defaults_file, data, as_user, user_password)) try: command = self.create_restore_command_call(backup_entry.data_path, restore_defaults_file, backup_entry.profile.defaults_file) result = self._context.ctrl_be.server_helper.execute_command(command, as_user=self._context.mysql_user, user_password=self._context.ctrl_be.password_handler.get_password_for("file"), output_handler=output_handler) finally: try: self.perform_as_user(self._context.mysql_user, lambda as_user, user_password: self._context.ctrl_be.server_helper.delete_file(restore_defaults_file, as_user, user_password)) except Exception, e: if output_handler: output_handler("Could not delete temporary defaults file %s: %s\n" % (restore_defaults_file, e))
def on_change(self): if self.dlg_type == OpenDirectory: self.selection = self.curdir.get_string_value() else: selid = self.flist.get_selected_node() if selid: fname = selid.get_string(0) self.selection = joinpath(self.curdir.get_string_value(), fname)
def create_backup_command_call(self, profile, type, to_schedule, filename=None): # If the command is not to be scheduled it will return the direct call to # the mysqlbackup command if not to_schedule: return super(WBBackupWindowsInterface, self).create_backup_command_call(profile, type, to_schedule, filename) cmd_data = [] script_name = joinpath(parentdir(self._context.server_profile.config_file_path), "mysqlwbbackup.vbs") cmd_data.append('\\"%s\\"' % script_name) # Uses the configuration file for the backup (MUST be the 1st option) cmd_data.append('%s.cnf' % profile._uuid) # Creates the values for compress and incremental compress_incremental = "0 0" if type == 'full': # The compress option is set only for full backups when apply-log is not # enabled, this is because --compress will be ignored anyway if profile.compress and not profile.apply_log: # 1 to indicate compress, 0 to indicate NOT incremental compress_incremental = '1 0' elif type == 'incremental': compress_incremental = "0 1" cmd_data.append(compress_incremental) # apply-log is only used on full backups when enabled if profile.apply_log and type == 'full': cmd_data.append('backup-and-apply-log') else: cmd_data.append('backup') # If a filename is explicitly requested, then use it if filename: cmd_data.append(filename) return " ".join(cmd_data)
def _mark_incremental_applied(self, incremental_path): # if mysqlbackup some day adds this internally, this should be changed to only do it for older versions self.perform_as_user(self._context.mysql_user, lambda as_user, user_password: self._context.ctrl_be.server_helper.set_file_content(joinpath(incremental_path, "applied.txt"), "", as_user, user_password))
def chdir(self, fname, is_full_path): # import traceback # traceback.print_stack() success = False if fname is not None and fname != "": log_debug("Directory changed: " + fname + " was full path: " + str(is_full_path) + "\n") path = fname if is_full_path else joinpath( self.curdir.get_string_value(), fname) (success, target_is_file) = self.try_cd(path) # The change failed... but still could be a valid if not success: done = target_is_file # If the failure is because an attempt to cd to a file was done if target_is_file: # If saving a file, we need to confirm the user wants to override the existing file if self.dlg_type == SaveFile: if mforms.Utilities.show_warning( 'File Already Exist', "The file %s already exists.\n Do you want to replace it?" % path, "Yes", "No", "") != mforms.ResultOk: done = False # When saving a file, an invalid path could mean a new file, we need to # check if the parent folder exists and if so... then we are done! elif self.dlg_type == SaveFile: (done, target_is_file) = self.try_cd(parentdir(path)) if not done: mforms.Utilities.show_warning( 'Invalid Path', "The path to %s is invalid." % path, "Ok", "", "") # Done will be true when: # - OpenFile on a file path # - SaveFile on an existing path and user indicated to override # - SaveFile on an unexisting path with a valid directory if done: self.selection = path self.form.close() return else: log_debug("Directory not changed\n") # Updates the file list only in case a cd has been done if success or fname is None: curdir = self.cwd() log_debug("chdir: Current dir is: " + curdir + "\n") #if curdir: # if curdir[-1] != "/": # curdir += "/" self.update_text(curdir) self._invalid_text = False self.flist.clear() (disr, files) = ((), ()) entries = self.ls(curdir) dirs = [ d['name'] for d in entries if d['isDir'] == 1 and d['name'] != ".." and d['name'] != "." ] files = [ f['name'] for f in entries if f['isDir'] == 0 and f['name'] != ".." and f['name'] != "." ] dirs.sort() files.sort() row_id = self.flist.add_node() row_id.set_icon_path(0, 'folder') row_id.set_string(0, '..') for d in dirs: row_id = self.flist.add_node() row_id.set_icon_path(0, 'folder') row_id.set_string(0, d) for f in files: row_id = self.flist.add_node() row_id.set_string(0, f)