diff --git a/modoboa_installer/scripts/__init__.py b/modoboa_installer/scripts/__init__.py index 097b369..15201c4 100644 --- a/modoboa_installer/scripts/__init__.py +++ b/modoboa_installer/scripts/__init__.py @@ -25,11 +25,12 @@ def install(appname, config, upgrade, restore): utils.printcolor(u"{}".format(inst), utils.RED) sys.exit(1) + def backup(config, bashArg, nomail): """Backup instance""" try: script = importlib.import_module( - "modoboa_installer.scripts.backup") + "modoboa_installer.scripts.backup") except ImportError: print("Error importing backup") try: @@ -38,6 +39,7 @@ def backup(config, bashArg, nomail): utils.printcolor(u"{}".format(inst), utils.RED) sys.exit(1) + def restore(restore): """Restore instance""" try: @@ -49,4 +51,4 @@ def restore(restore): getattr(script, "Restore")(restore) except utils.FatalError as inst: utils.printcolor(u"{}".format(inst), utils.RED) - sys.exit(1) \ No newline at end of file + sys.exit(1) diff --git a/modoboa_installer/scripts/amavis.py b/modoboa_installer/scripts/amavis.py index 3f19596..3b15c41 100644 --- a/modoboa_installer/scripts/amavis.py +++ b/modoboa_installer/scripts/amavis.py @@ -44,8 +44,10 @@ class Amavis(base.Installer): if package.backend.FORMAT == "deb": amavisCustomConf = os.path.join(self.restore, "custom/99-custom") if self.restore and os.path.isfile(amavisCustomConf): - utils.copy_file(amavisCustomConf, os.path.join(self.config_dir, "/conf.d")) - utils.printcolor("Custom amavis configuration restored", utils.GREEN) + utils.copy_file(amavisCustomConf, os.path.join( + self.config_dir, "/conf.d")) + utils.printcolor( + "Custom amavis configuration restored", utils.GREEN) return [ "conf.d/05-node_id", "conf.d/15-content_filter_mode", "conf.d/50-user"] @@ -74,12 +76,16 @@ class Amavis(base.Installer): def get_sql_schema_path(self): """Return schema path.""" if self.restore: - utils.printcolor("Trying to restore amavis database from backup", utils.MAGENTA) - amavisDbBackupPath = os.path.join(self.restore, "databases/amavis.sql") + utils.printcolor( + "Trying to restore amavis database from backup", utils.MAGENTA) + amavisDbBackupPath = os.path.join( + self.restore, "databases/amavis.sql") if os.path.isfile(amavisDbBackupPath): - utils.printcolor("Amavis database backup found ! Restoring...", utils.GREEN) + utils.printcolor( + "Amavis database backup found ! Restoring...", utils.GREEN) return amavisDbBackupPath - utils.printcolor("Amavis database backup not found, creating empty database", utils.RED) + utils.printcolor( + "Amavis database backup not found, creating empty database", utils.RED) version = package.backend.get_installed_version("amavisd-new") if version is None: @@ -94,7 +100,7 @@ class Amavis(base.Installer): path = self.get_file_path( "amavis_{}_{}.sql".format(self.dbengine, version)) if not os.path.exists(path): - raise utils.FatalError("Failed to find amavis database schema") + raise utils.FatalError("Failed to find amavis database schema") return path def pre_run(self): diff --git a/modoboa_installer/scripts/backup.py b/modoboa_installer/scripts/backup.py index 40cf20f..7984372 100644 --- a/modoboa_installer/scripts/backup.py +++ b/modoboa_installer/scripts/backup.py @@ -10,23 +10,24 @@ import sys from .. import database from .. import utils -#TODO: have version of each modoboa componenents saved into the config file to restore the same version +# TODO: have version of each modoboa componenents saved into the config file to restore the same version + class Backup(): -#Backup structure ( {optional} ): -#{{backup_folder}} -#|| -#||--> installer.cfg -#||--> custom -# |--> { (copy of) /etc/amavis/conf.d/99-custom } -# |--> { (copy of) /etc/postfix/custom_whitelist.cidr } -#||--> databases -# |--> modoboa.sql -# |--> { amavis.sql } -# |--> { spamassassin.sql } -#||--> mails -# |--> vmails + # Backup structure ( {optional} ): + # {{backup_folder}} + # || + # ||--> installer.cfg + # ||--> custom + # |--> { (copy of) /etc/amavis/conf.d/99-custom } + # |--> { (copy of) /etc/postfix/custom_whitelist.cidr } + # ||--> databases + # |--> modoboa.sql + # |--> { amavis.sql } + # |--> { spamassassin.sql } + # ||--> mails + # |--> vmails def __init__(self, config, bashArg, nomail): self.config = config @@ -39,39 +40,40 @@ class Backup(): self.isBash = True self.bash = bashArg - def preparePath(self): pw = pwd.getpwnam("root") for dir in self.BACKUPDIRECTORY: - utils.mkdir_safe(os.path.join(self.destinationPath,dir), - stat.S_IRWXU | stat.S_IRWXG, pw[2], pw[3]) - + utils.mkdir_safe(os.path.join(self.destinationPath, dir), + stat.S_IRWXU | stat.S_IRWXG, pw[2], pw[3]) def validatePath(self, path): """Check basic condition for backup directory""" - try : + try: pathExists = os.path.exists(path) except: print("Provided path is not recognized...") return False - + if pathExists and os.path.isfile(path): - print("Error, you provided a file instead of a directory!") - return False + print("Error, you provided a file instead of a directory!") + return False if not pathExists: if not self.isBash: - createDir = input(f"\"{path}\" doesn't exists, would you like to create it ? [Y/n]\n").lower() + createDir = input( + f"\"{path}\" doesn't exists, would you like to create it ? [Y/n]\n").lower() if self.isBash or (not self.isBash and (createDir == "y" or createDir == "yes")): pw = pwd.getpwnam("root") - utils.mkdir_safe(path, stat.S_IRWXU | stat.S_IRWXG, pw[2], pw[3]) + utils.mkdir_safe(path, stat.S_IRWXU | + stat.S_IRWXG, pw[2], pw[3]) else: return False if len(os.listdir(path)) != 0: if not self.isBash: - delDir = input("Warning : backup folder is not empty, it will be purged if you continue... [Y/n]\n").lower() + delDir = input( + "Warning : backup folder is not empty, it will be purged if you continue... [Y/n]\n").lower() if self.isBash or (not self.isBash and (delDir == "y" or delDir == "yes")): shutil.rmtree(path) else: @@ -82,7 +84,6 @@ class Backup(): self.preparePath() return True - def setPath(self): """Setup backup directory""" if self.isBash: @@ -90,7 +91,7 @@ class Backup(): date = datetime.datetime.now().strftime("%m_%d_%Y_%H_%M") path = f"/modoboa_backup/backup_{date}/" self.validatePath(path) - else : + else: validate = self.validatePath(self.bash) if not validate: print("provided bash is not right, exiting...") @@ -102,16 +103,15 @@ class Backup(): print("Enter backup path, please provide an empty folder.") print("CTRL+C to cancel") user_value = utils.user_input("-> ") - def backupConfigFile(self): utils.copy_file("installer.cfg", self.destinationPath) - def backupMails(self): if self.nomail: - utils.printcolor("Skipping mail backup, no-mail argument provided", utils.MAGENTA) + utils.printcolor( + "Skipping mail backup, no-mail argument provided", utils.MAGENTA) return utils.printcolor("Backing up mails", utils.MAGENTA) @@ -120,26 +120,27 @@ class Backup(): if not os.path.exists(home_path) or os.path.isfile(home_path): utils.printcolor("Error backing up Email, provided path " - f" ({home_path}) seems not right...", utils.RED) - + f" ({home_path}) seems not right...", utils.RED) + else: dst = os.path.join(self.destinationPath, "mails/") if os.path.exists(dst): shutil.rmtree(dst) - + shutil.copytree(home_path, dst) utils.printcolor("Mail backup complete!", utils.GREEN) - def backupCustomConfig(self): """Custom config : - Amavis : /etc/amavis/conf.d/99-custom - Postwhite : /etc/postwhite.conf Feel free to suggest to add others!""" - utils.printcolor("Backing up some custom configuration...", utils.MAGENTA) + utils.printcolor( + "Backing up some custom configuration...", utils.MAGENTA) - custom_path = os.path.join(self.destinationPath, self.BACKUPDIRECTORY[0]) + custom_path = os.path.join( + self.destinationPath, self.BACKUPDIRECTORY[0]) """AMAVIS""" amavis_custom = "/etc/amavis/conf.d/99-custom" @@ -153,7 +154,6 @@ class Backup(): utils.copy_file(postswhite_custom, custom_path) utils.printcolor("Postwhite configuration saved!", utils.GREEN) - def backupDBs(self): """Backing up databases""" @@ -166,27 +166,30 @@ class Backup(): dbname = self.config.get("modoboa", "dbname") dbuser = self.config.get("modoboa", "dbuser") dbpasswd = self.config.get("modoboa", "dbpassword") - backend.dumpDatabase(dbname, dbuser, dbpasswd, os.path.join(dump_path,"modoboa.sql")) + backend.dumpDatabase(dbname, dbuser, dbpasswd, + os.path.join(dump_path, "modoboa.sql")) """Amavis""" if (self.config.has_option("amavis", "enabled") and - self.config.getboolean("amavis", "enabled")): + self.config.getboolean("amavis", "enabled")): dbname = self.config.get("amavis", "dbname") dbuser = self.config.get("amavis", "dbuser") dbpasswd = self.config.get("amavis", "dbpassword") - backend.dumpDatabase(dbname, dbuser, dbpasswd, os.path.join(dump_path,"amavis.sql")) + backend.dumpDatabase(dbname, dbuser, dbpasswd, + os.path.join(dump_path, "amavis.sql")) """SpamAssassin""" if (self.config.has_option("spamassassin", "enabled") and - self.config.getboolean("spamassassin", "enabled")): + self.config.getboolean("spamassassin", "enabled")): dbname = self.config.get("spamassassin", "dbname") dbuser = self.config.get("spamassassin", "dbuser") dbpasswd = self.config.get("spamassassin", "dbpassword") - backend.dumpDatabase(dbname, dbuser, dbpasswd, os.path.join(dump_path,"spamassassin.sql")) + backend.dumpDatabase(dbname, dbuser, dbpasswd, + os.path.join(dump_path, "spamassassin.sql")) def backupCompletion(self): utils.printcolor("Backup process done, your backup is availible here:" - f"--> {self.destinationPath}", utils.GREEN) + f"--> {self.destinationPath}", utils.GREEN) def run(self): self.setPath() @@ -195,5 +198,3 @@ class Backup(): self.backupCustomConfig() self.backupDBs() self.backupCompletion() - - diff --git a/modoboa_installer/scripts/dovecot.py b/modoboa_installer/scripts/dovecot.py index 2024bcb..241ee7e 100644 --- a/modoboa_installer/scripts/dovecot.py +++ b/modoboa_installer/scripts/dovecot.py @@ -90,19 +90,22 @@ class Dovecot(base.Installer): """Additional tasks.""" mail_dir = os.path.join(self.restore, "mails/") if self.restore and len(os.listdir(mail_dir)) > 0: - utils.printcolor("Copying mail backup over dovecot directory", utils.GREEN) - + utils.printcolor( + "Copying mail backup over dovecot directory", utils.GREEN) + if os.path.exists(self.home_dir): shutil.rmtree(self.home_dir) shutil.copytree(mail_dir, self.home_dir) - #Resetting permission for vmail + # Resetting permission for vmail for dirpath, dirnames, filenames in os.walk(self.home_dir): shutil.chown(dirpath, self.user, self.user) for filename in filenames: - shutil.chown(os.path.join(dirpath, filename), self.user, self.user) + shutil.chown(os.path.join(dirpath, filename), + self.user, self.user) elif self.restore: - utils.printcolor("It seems that mails were not backed up, skipping mail restoration.", utils.MAGENTA) + utils.printcolor( + "It seems that mails were not backed up, skipping mail restoration.", utils.MAGENTA) if self.dbengine == "postgres": dbname = self.config.get("modoboa", "dbname") diff --git a/modoboa_installer/scripts/modoboa.py b/modoboa_installer/scripts/modoboa.py index dadbf4f..3f1f164 100644 --- a/modoboa_installer/scripts/modoboa.py +++ b/modoboa_installer/scripts/modoboa.py @@ -176,15 +176,18 @@ class Modoboa(base.Installer): self.backend.grant_access( self.config.get("amavis", "dbname"), self.dbuser) - def get_sql_schema_path(self): if self.restore: - utils.printcolor("Trying to restore modoboa database from backup", utils.MAGENTA) - modoboaDbBackupPath = os.path.join(self.restore, "databases/modoboa.sql") + utils.printcolor( + "Trying to restore modoboa database from backup", utils.MAGENTA) + modoboaDbBackupPath = os.path.join( + self.restore, "databases/modoboa.sql") if os.path.isfile(modoboaDbBackupPath): - utils.printcolor("Modoboa database backup found ! Restoring...", utils.GREEN) + utils.printcolor( + "Modoboa database backup found ! Restoring...", utils.GREEN) return modoboaDbBackupPath - utils.printcolor("Modoboa database backup not found, creating empty database", utils.RED) + utils.printcolor( + "Modoboa database backup not found, creating empty database", utils.RED) return super().get_sql_schema_path()() diff --git a/modoboa_installer/scripts/postwhite.py b/modoboa_installer/scripts/postwhite.py index 49c4155..d6e6a67 100644 --- a/modoboa_installer/scripts/postwhite.py +++ b/modoboa_installer/scripts/postwhite.py @@ -46,10 +46,12 @@ class Postwhite(base.Installer): self.install_from_archive(SPF_TOOLS_REPOSITORY, install_dir) postw_dir = self.install_from_archive( POSTWHITE_REPOSITORY, install_dir) - postwhiteBackupConf = os.path.join(self.restore, "custom/postwhite.conf") + postwhiteBackupConf = os.path.join( + self.restore, "custom/postwhite.conf") if self.restore and os.path.isfile(postwhiteBackupConf): utils.copy_file(postwhiteBackupConf, "/etc") - utils.printcolor("postwhite.conf restored from backup", utils.GREEN) + utils.printcolor( + "postwhite.conf restored from backup", utils.GREEN) else: utils.copy_file(os.path.join(postw_dir, "postwhite.conf"), "/etc") postw_bin = os.path.join(postw_dir, "postwhite") diff --git a/modoboa_installer/scripts/restore.py b/modoboa_installer/scripts/restore.py index 028abe7..7f88520 100644 --- a/modoboa_installer/scripts/restore.py +++ b/modoboa_installer/scripts/restore.py @@ -2,6 +2,7 @@ import os import sys from .. import utils + class Restore: def __init__(self, restore): """Restoring pre-check (backup integriety)""" @@ -11,7 +12,8 @@ class Restore: try: if not os.path.isdir(restore): - utils.printcolor("Provided path is not a directory !", utils.RED) + utils.printcolor( + "Provided path is not a directory !", utils.RED) sys.exit(1) except: utils.printcolor("Provided path is not right...", utils.RED) @@ -20,10 +22,12 @@ class Restore: try: modobasql_file = os.path.join(restore, "databases/modoboa.sql") if not os.path.isfile(modobasql_file): - utils.printcolor(modobasql_file +" not found, please check your backup", utils.RED) + utils.printcolor( + modobasql_file + " not found, please check your backup", utils.RED) sys.exit(1) except: - utils.printcolor(modobasql_file + " not found, please check your backup", utils.RED) + utils.printcolor(modobasql_file + + " not found, please check your backup", utils.RED) sys.exit(1) - #Everything seems allright here, proceding... \ No newline at end of file + # Everything seems allright here, proceding... diff --git a/modoboa_installer/scripts/spamassassin.py b/modoboa_installer/scripts/spamassassin.py index adf1242..00843ce 100644 --- a/modoboa_installer/scripts/spamassassin.py +++ b/modoboa_installer/scripts/spamassassin.py @@ -26,12 +26,16 @@ class Spamassassin(base.Installer): def get_sql_schema_path(self): """Return SQL schema.""" if self.restore: - utils.printcolor("Trying to restore spamassassin database from backup", utils.MAGENTA) - amavisDbBackupPath = os.path.join(self.restore, "databases/spamassassin.sql") + utils.printcolor( + "Trying to restore spamassassin database from backup", utils.MAGENTA) + amavisDbBackupPath = os.path.join( + self.restore, "databases/spamassassin.sql") if os.path.isfile(amavisDbBackupPath): - utils.printcolor("Spamassassin database backup found ! Restoring...", utils.GREEN) + utils.printcolor( + "Spamassassin database backup found ! Restoring...", utils.GREEN) return amavisDbBackupPath - utils.printcolor("Spamassassin database backup not found, creating empty database", utils.RED) + utils.printcolor( + "Spamassassin database backup not found, creating empty database", utils.RED) if self.dbengine == "postgres": fname = "bayes_pg.sql" diff --git a/modoboa_installer/utils.py b/modoboa_installer/utils.py index 48260d2..babea78 100644 --- a/modoboa_installer/utils.py +++ b/modoboa_installer/utils.py @@ -106,12 +106,14 @@ def mkdir(path, mode, uid, gid): os.chmod(path, mode) os.chown(path, uid, gid) + def mkdir_safe(path, mode, uid, gid): """Create a directory. Safe way (-p)""" if not os.path.exists(path): os.makedirs(os.path.abspath(path), mode) mkdir(path, mode, uid, gid) + def make_password(length=16): """Create a random password.""" return "".join( @@ -188,7 +190,7 @@ def check_config_file(dest, interactive=False, upgrade=False, backup=False, rest "You cannot restore an existing installation without a " f"configuration file. (file : {dest} has not been found...", RED) sys.exit(1) - + printcolor( "Configuration file {} not found, creating new one." .format(dest), YELLOW) diff --git a/run.py b/run.py index 31608d8..33939ac 100755 --- a/run.py +++ b/run.py @@ -17,6 +17,7 @@ from modoboa_installer import ssl from modoboa_installer import system from modoboa_installer import utils + def installation_disclaimer(args, config): """Display installation disclaimer.""" hostname = config.get("general", "hostname") @@ -44,6 +45,7 @@ def upgrade_disclaimer(config): " will be impacted:", utils.BLUE ) + def backup_disclamer(): """Display backup disclamer. """ utils.printcolor( @@ -51,6 +53,7 @@ def backup_disclamer(): " !! You should really transfer the backup somewhere else..." " Custom configuration (like to postfix) won't be saved.", utils.BLUE) + def restore_disclamer(): """Display restore disclamer. """ utils.printcolor( @@ -58,6 +61,7 @@ def restore_disclamer(): "If a new version has been released in between, please update your database !", utils.BLUE) + def main(input_args): """Install process.""" parser = argparse.ArgumentParser() @@ -96,7 +100,7 @@ def main(input_args): parser.add_argument( "--no-mail", action="store_true", default=False, help="Disable mail backup (save space)") - parser.add_argument( + parser.add_argument( "--restore", type=str, metavar="path", help="Restore a previously backup up modoboa instance on a NEW machine. You Must provide backup directory" ) @@ -109,16 +113,17 @@ def main(input_args): if not args.backup and (args.bash != None or args.sbash or args.no_mail): utils.printcolor("You provided --bash or --sbash without --backup, " - "if you want to do a backup, please provide --backup!", utils.RED) + "if you want to do a backup, please provide --backup!", utils.RED) return - elif args.bash != None and args.sbash : + elif args.bash != None and args.sbash: utils.printcolor("You provided --bash PATH and --sbash at the same time. " - "Please provided only one!", utils.RED) + "Please provided only one!", utils.RED) return elif args.bash == "TRUE": - utils.printcolor("You can't pick *TRUE* as backup directory !", utils.RED) - - #Restore prep + utils.printcolor( + "You can't pick *TRUE* as backup directory !", utils.RED) + + # Restore prep isRestoring = False if args.restore != None: isRestoring = True @@ -126,10 +131,11 @@ def main(input_args): if not os.path.exists(args.configfile): utils.printcolor("installer.cfg from backup not found!", utils.RED) sys.exit(1) - + utils.printcolor("Welcome to Modoboa installer!\n", utils.GREEN) - wasConfigFileAlreadyThere = utils.check_config_file(args.configfile, args.interactive, args.upgrade, args.backup, isRestoring) - + wasConfigFileAlreadyThere = utils.check_config_file( + args.configfile, args.interactive, args.upgrade, args.backup, isRestoring) + if args.stop_after_configfile_check or (not wasConfigFileAlreadyThere and args.backup): return @@ -159,7 +165,7 @@ def main(input_args): scripts.restore(args.restore) else: installation_disclaimer(args, config) - + # Show concerned components components = [] for section in config.sections(): @@ -207,5 +213,6 @@ def main(input_args): .format(config.get("general", "hostname")), utils.GREEN) + if __name__ == "__main__": main(sys.argv[1:])