Formating, force outdated config check

This commit is contained in:
Spitap
2023-03-12 00:30:04 +01:00
parent 0b29f74e08
commit 6261066ccd
7 changed files with 61 additions and 53 deletions

View File

@@ -54,12 +54,6 @@ run the following command::
$ ./run.py --stop-after-configfile-check <your domain> $ ./run.py --stop-after-configfile-check <your domain>
If you updated your installer, your config file might be outdated.
The program will exit after the update, so you can check the config file
before continuing. To perform the update, run the following command::
$ ./run.py --update-configfile <your domain>
An interactive mode is also available:: An interactive mode is also available::
$ ./run.py --interactive <your domain> $ ./run.py --interactive <your domain>

View File

@@ -44,8 +44,7 @@ class Backup:
path_exists = os.path.exists(path) path_exists = os.path.exists(path)
if path_exists and os.path.isfile(path): if path_exists and os.path.isfile(path):
utils.printcolor( utils.error("Error, you provided a file instead of a directory!")
"Error, you provided a file instead of a directory!", utils.RED)
return False return False
if not path_exists: if not path_exists:
@@ -58,9 +57,7 @@ class Backup:
utils.mkdir_safe(path, stat.S_IRWXU | utils.mkdir_safe(path, stat.S_IRWXU |
stat.S_IRWXG, pw[2], pw[3]) stat.S_IRWXG, pw[2], pw[3])
else: else:
utils.printcolor( utils.error("Error, backup directory not present.")
"Error, backup directory not present.", utils.RED
)
return False return False
if len(os.listdir(path)) != 0: if len(os.listdir(path)) != 0:
@@ -80,9 +77,7 @@ class Backup:
shutil.rmtree(os.path.join(path, "databases"), shutil.rmtree(os.path.join(path, "databases"),
ignore_errors=False) ignore_errors=False)
else: else:
utils.printcolor( utils.error("Error: backup directory not clean.")
"Error: backup directory not clean.", utils.RED
)
return False return False
self.backup_path = path self.backup_path = path
@@ -131,8 +126,8 @@ class Backup:
home_path = self.config.get("dovecot", "home_dir") home_path = self.config.get("dovecot", "home_dir")
if not os.path.exists(home_path) or os.path.isfile(home_path): if not os.path.exists(home_path) or os.path.isfile(home_path):
utils.printcolor("Error backing up Email, provided path " utils.error("Error backing up Email, provided path "
f" ({home_path}) seems not right...", utils.RED) f" ({home_path}) seems not right...")
else: else:
dst = os.path.join(self.backup_path, "mails/") dst = os.path.join(self.backup_path, "mails/")

View File

@@ -131,7 +131,7 @@ class Installer(object):
return return
exitcode, output = package.backend.install_many(packages) exitcode, output = package.backend.install_many(packages)
if exitcode: if exitcode:
utils.printcolor("Failed to install dependencies", utils.RED) utils.error("Failed to install dependencies")
sys.exit(1) sys.exit(1)
def get_config_files(self): def get_config_files(self):

View File

@@ -13,14 +13,14 @@ class Restore:
""" """
if not os.path.isdir(restore): if not os.path.isdir(restore):
utils.printcolor( utils.error(
"Provided path is not a directory !", utils.RED) "Provided path is not a directory !")
sys.exit(1) sys.exit(1)
modoba_sql_file = os.path.join(restore, "databases/modoboa.sql") modoba_sql_file = os.path.join(restore, "databases/modoboa.sql")
if not os.path.isfile(modoba_sql_file): if not os.path.isfile(modoba_sql_file):
utils.printcolor( utils.error(
modoba_sql_file + " not found, please check your backup", utils.RED) modoba_sql_file + " not found, please check your backup")
sys.exit(1) sys.exit(1)
# Everything seems alright here, proceeding... # Everything seems alright here, proceeding...

View File

@@ -90,7 +90,7 @@ class LetsEncryptCertificate(CertificateBackend):
elif "centos" in name: elif "centos" in name:
package.backend.install("certbot") package.backend.install("certbot")
else: else:
utils.printcolor("Failed to install certbot, aborting.", utils.RED) utils.printcolor("Failed to install certbot, aborting.")
sys.exit(1) sys.exit(1)
# Nginx plugin certbot # Nginx plugin certbot
if ( if (

View File

@@ -177,7 +177,7 @@ def check_config_file(dest, interactive=False, upgrade=False, backup=False, rest
"""Create a new installer config file if needed.""" """Create a new installer config file if needed."""
is_present = True is_present = True
if os.path.exists(dest): if os.path.exists(dest):
return is_present return is_present, update_config(dest, False)
if upgrade: if upgrade:
printcolor( printcolor(
"You cannot upgrade an existing installation without a " "You cannot upgrade an existing installation without a "
@@ -198,7 +198,7 @@ def check_config_file(dest, interactive=False, upgrade=False, backup=False, rest
"Configuration file {} not found, creating new one." "Configuration file {} not found, creating new one."
.format(dest), YELLOW) .format(dest), YELLOW)
gen_config(dest, interactive) gen_config(dest, interactive)
return is_present return is_present, None
def has_colours(stream): def has_colours(stream):
@@ -340,7 +340,7 @@ def load_config_template(interactive):
return config return config
def update_config(path): def update_config(path, apply_update=True):
"""Update an existing config file.""" """Update an existing config file."""
config = configparser.ConfigParser() config = configparser.ConfigParser()
with open(path) as fp: with open(path) as fp:
@@ -353,35 +353,41 @@ def update_config(path):
update = False update = False
dropped_sections = list(set(old_sections) - set(new_sections)) dropped_sections = list(set(old_sections) - set(new_sections))
added_sections = list(set(new_sections) - set(old_sections))
if len(dropped_sections) > 0: if len(dropped_sections) > 0 and not apply_update:
printcolor("Following section(s) will not be ported " printcolor("Following section(s) will not be ported "
"due to being deleted or renamed: " + "due to being deleted or renamed: " +
', '.join(dropped_sections), ', '.join(dropped_sections),
RED) RED)
if len(dropped_sections) + len(added_sections) > 0:
update = True
for section in new_sections: for section in new_sections:
if section in old_sections: if section in old_sections:
new_options = new_config.options(section) new_options = new_config.options(section)
old_options = config.options(section) old_options = config.options(section)
dropped_options = list(set(old_options) - set(new_options)) dropped_options = list(set(old_options) - set(new_options))
added_options = list(set(new_options) - set(old_sections))
if len(dropped_options) > 0: if len(dropped_options) > 0 and not apply_update:
printcolor(f"Following option(s) from section: {section}, " printcolor(f"Following option(s) from section: {section}, "
"will not be ported due to being " "will not be ported due to being "
"deleted or renamed: " + "deleted or renamed: " +
', '.join(dropped_options), ', '.join(dropped_options),
RED) RED)
if len(dropped_options) + len(added_options) > 0:
update = True
for option in new_options: if apply_update:
if option in old_options: for option in new_options:
value = config.get(section, option, raw=True) if option in old_options:
if value != new_config.get(section, option, raw=True): value = config.get(section, option, raw=True)
update = True if value != new_config.get(section, option, raw=True):
new_config.set(section, option, value) update = True
new_config.set(section, option, value)
if update: if update and apply_update:
# Backing up old config file # Backing up old config file
date = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S") date = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
dest = f"{os.path.splitext(path)[0]}_{date}.old" dest = f"{os.path.splitext(path)[0]}_{date}.old"
@@ -391,13 +397,19 @@ def update_config(path):
with open(path, "w") as configfile: with open(path, "w") as configfile:
new_config.write(configfile) new_config.write(configfile)
# Set file owner to running user and group, and set config file permission to 600 # Set file owner to running u+g, and set config file permission to 600
current_username = getpass.getuser() current_username = getpass.getuser()
current_user = pwd.getpwnam(current_username) current_user = pwd.getpwnam(current_username)
os.chown(dest, current_user[2], current_user[3]) os.chown(dest, current_user[2], current_user[3])
os.chmod(dest, stat.S_IRUSR | stat.S_IWUSR) os.chmod(dest, stat.S_IRUSR | stat.S_IWUSR)
return dest return dest
elif update and not apply_update:
# Simply check if current config file is outdated
return True
elif not update and not apply_update:
return False
return None return None

39
run.py
View File

@@ -116,6 +116,15 @@ def backup_system(config, args):
scripts.backup(app, config, backup_path) scripts.backup(app, config, backup_path)
def config_file_update_complete(backup_location):
utils.printcolor("Update complete. It seems successful.",
utils.BLUE)
if backup_location is not None:
utils.printcolor("You will find your old config file "
f"here: {backup_location}",
utils.BLUE)
def main(input_args): def main(input_args):
"""Install process.""" """Install process."""
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@@ -134,10 +143,6 @@ def main(input_args):
parser.add_argument( parser.add_argument(
"--stop-after-configfile-check", action="store_true", default=False, "--stop-after-configfile-check", action="store_true", default=False,
help="Check configuration, generate it if needed and exit") help="Check configuration, generate it if needed and exit")
parser.add_argument(
"--update-configfile", action="store_true", default=False,
help="Attempt to update the config file. "
"Installer will stop after performing the update.")
parser.add_argument( parser.add_argument(
"--interactive", action="store_true", default=False, "--interactive", action="store_true", default=False,
help="Generate configuration file with user interaction") help="Generate configuration file with user interaction")
@@ -184,18 +189,7 @@ def main(input_args):
utils.success("Welcome to Modoboa installer!\n") utils.success("Welcome to Modoboa installer!\n")
# Update configfile is_config_file_available, outdate_config = utils.check_config_file(
if args.update_configfile:
backup_location = utils.update_config(args.configfile)
utils.printcolor("Update complete. It seems successful.",
utils.BLUE)
if backup_location is not None:
utils.printcolor("You will find your old config file "
f"here: {backup_location}",
utils.BLUE)
return
is_config_file_available = utils.check_config_file(
args.configfile, args.interactive, args.upgrade, args.backup, is_restoring) args.configfile, args.interactive, args.upgrade, args.backup, is_restoring)
if not is_config_file_available and ( if not is_config_file_available and (
@@ -203,6 +197,19 @@ def main(input_args):
utils.error("No config file found.") utils.error("No config file found.")
return return
# Check if config is outdated and ask user if it needs to be updated
if is_config_file_available and outdate_config:
answer = utils.user_input("It seems that your config file is outdated. "
"Would you like to update it? (Y/n) ")
if answer.lower().startswith("y"):
config_file_update_complete(utils.update_config(args.configfile))
answer = utils.user_input("Would you like to stop to review the updated config? (Y/n)")
if answer.lower().startswith("y"):
return
else:
utils.error("You might encounter unexpected errors ! "
"Make sur to update your config before opening an issue!")
if args.stop_after_configfile_check: if args.stop_after_configfile_check:
return return