diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 054171133..725f14a03 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1735,9 +1735,6 @@ tools: --skip: help: Skip specified migrations (to be used only if you know what you are doing) action: store_true - --revert: - help: Attempt to revert already-ran specified migrations (to be used only if you know what you are doing) - action: store_true --force-rerun: help: Re-run already-ran specified migration (to be used only if you know what you are doing) action: store_true diff --git a/locales/en.json b/locales/en.json index 471f0f9dc..850d89032 100644 --- a/locales/en.json +++ b/locales/en.json @@ -297,7 +297,6 @@ "log_user_permission_remove": "Update '{}' permission", "log_tools_maindomain": "Make '{}' as main domain", "log_tools_migrations_migrate_forward": "Migrate forward", - "log_tools_migrations_migrate_backward": "Migrate backward", "log_tools_postinstall": "Postinstall your YunoHost server", "log_tools_upgrade": "Upgrade system packages", "log_tools_shutdown": "Shutdown your server", @@ -384,7 +383,6 @@ "migrations_not_pending_cant_skip": "Those migrations are not pending so cannot be skipped: {ids}", "migrations_pending_cant_revert_or_rerun": "Those migrations are still pending so cannot be reverted or reran: {ids}", "migrations_running_forward": "Running migration {id}…", - "migrations_running_backward": "Attempting to revert migration {id}…", "migrations_skip_migration": "Skipping migration {id}…", "migrations_success_forward": "Successfully ran migration {id}!", "migrations_success_revert": "Successfully reverted migration {id}!", diff --git a/src/yunohost/data_migrations/0001_change_cert_group_to_sslcert.py b/src/yunohost/data_migrations/0001_change_cert_group_to_sslcert.py index 6485861b7..4338e10f3 100644 --- a/src/yunohost/data_migrations/0001_change_cert_group_to_sslcert.py +++ b/src/yunohost/data_migrations/0001_change_cert_group_to_sslcert.py @@ -10,10 +10,11 @@ class MyMigration(Migration): all_certificate_files = glob.glob("/etc/yunohost/certs/*/*.pem") - def forward(self): - for filename in self.all_certificate_files: - chown(filename, uid="root", gid="ssl-cert") - - def backward(self): - for filename in self.all_certificate_files: - chown(filename, uid="root", gid="metronome") + def run(self): + try: + for filename in self.all_certificate_files: + chown(filename, uid="root", gid="ssl-cert") + except Exception: + for filename in self.all_certificate_files: + chown(filename, uid="root", gid="metronome") + raise diff --git a/src/yunohost/data_migrations/0002_migrate_to_tsig_sha256.py b/src/yunohost/data_migrations/0002_migrate_to_tsig_sha256.py index cc5d4c19b..65158ba2c 100644 --- a/src/yunohost/data_migrations/0002_migrate_to_tsig_sha256.py +++ b/src/yunohost/data_migrations/0002_migrate_to_tsig_sha256.py @@ -19,7 +19,7 @@ class MyMigration(Migration): "Migrate Dyndns stuff from MD5 TSIG to SHA512 TSIG" - def migrate(self, dyn_host="dyndns.yunohost.org", domain=None, private_key_path=None): + def run(self, dyn_host="dyndns.yunohost.org", domain=None, private_key_path=None): if domain is None or private_key_path is None: try: diff --git a/src/yunohost/data_migrations/0003_migrate_to_stretch.py b/src/yunohost/data_migrations/0003_migrate_to_stretch.py index 0db6cfd6d..19793bbec 100644 --- a/src/yunohost/data_migrations/0003_migrate_to_stretch.py +++ b/src/yunohost/data_migrations/0003_migrate_to_stretch.py @@ -29,7 +29,7 @@ class MyMigration(Migration): mode = "manual" - def forward(self): + def run(self): self.logfile = "/var/log/yunohost/{}.log".format(self.name) diff --git a/src/yunohost/data_migrations/0004_php5_to_php7_pools.py b/src/yunohost/data_migrations/0004_php5_to_php7_pools.py index e916a9cd7..7bb9123ec 100644 --- a/src/yunohost/data_migrations/0004_php5_to_php7_pools.py +++ b/src/yunohost/data_migrations/0004_php5_to_php7_pools.py @@ -24,77 +24,77 @@ class MyMigration(Migration): dependencies = ["migrate_to_stretch"] - def forward(self): + def run(self): + try: + # Get list of php5 pool files + php5_pool_files = glob.glob("{}/*.conf".format(PHP5_POOLS)) - # Get list of php5 pool files - php5_pool_files = glob.glob("{}/*.conf".format(PHP5_POOLS)) + # Keep only basenames + php5_pool_files = [os.path.basename(f) for f in php5_pool_files] - # Keep only basenames - php5_pool_files = [os.path.basename(f) for f in php5_pool_files] + # Ignore the "www.conf" (default stuff, probably don't want to touch it ?) + php5_pool_files = [f for f in php5_pool_files if f != "www.conf"] - # Ignore the "www.conf" (default stuff, probably don't want to touch it ?) - php5_pool_files = [f for f in php5_pool_files if f != "www.conf"] + for f in php5_pool_files: - for f in php5_pool_files: + # Copy the files to the php7 pool + src = "{}/{}".format(PHP5_POOLS, f) + dest = "{}/{}".format(PHP7_POOLS, f) + copy2(src, dest) - # Copy the files to the php7 pool - src = "{}/{}".format(PHP5_POOLS, f) - dest = "{}/{}".format(PHP7_POOLS, f) - copy2(src, dest) + # Replace the socket prefix if it's found + c = "sed -i -e 's@{}@{}@g' {}".format(PHP5_SOCKETS_PREFIX, PHP7_SOCKETS_PREFIX, dest) + os.system(c) - # Replace the socket prefix if it's found - c = "sed -i -e 's@{}@{}@g' {}".format(PHP5_SOCKETS_PREFIX, PHP7_SOCKETS_PREFIX, dest) - os.system(c) + # Also add a comment that it was automatically moved from php5 + # (for human traceability and backward migration) + c = "sed -i '1i {}' {}".format(MIGRATION_COMMENT, dest) + os.system(c) - # Also add a comment that it was automatically moved from php5 - # (for human traceability and backward migration) - c = "sed -i '1i {}' {}".format(MIGRATION_COMMENT, dest) - os.system(c) + # Some old comments starting with '#' instead of ';' are not + # compatible in php7 + c = "sed -i 's/^#/;#/g' {}".format(dest) + os.system(c) - # Some old comments starting with '#' instead of ';' are not - # compatible in php7 - c = "sed -i 's/^#/;#/g' {}".format(dest) - os.system(c) + # Reload/restart the php pools + _run_service_command("restart", "php7.0-fpm") + _run_service_command("enable", "php7.0-fpm") + os.system("systemctl stop php5-fpm") + os.system("systemctl disable php5-fpm") + os.system("rm /etc/logrotate.d/php5-fpm") # We remove this otherwise the logrotate cron will be unhappy - # Reload/restart the php pools - _run_service_command("restart", "php7.0-fpm") - _run_service_command("enable", "php7.0-fpm") - os.system("systemctl stop php5-fpm") - os.system("systemctl disable php5-fpm") - os.system("rm /etc/logrotate.d/php5-fpm") # We remove this otherwise the logrotate cron will be unhappy + # Get list of nginx conf file + nginx_conf_files = glob.glob("/etc/nginx/conf.d/*.d/*.conf") + for f in nginx_conf_files: + # Replace the socket prefix if it's found + c = "sed -i -e 's@{}@{}@g' {}".format(PHP5_SOCKETS_PREFIX, PHP7_SOCKETS_PREFIX, f) + os.system(c) - # Get list of nginx conf file - nginx_conf_files = glob.glob("/etc/nginx/conf.d/*.d/*.conf") - for f in nginx_conf_files: - # Replace the socket prefix if it's found - c = "sed -i -e 's@{}@{}@g' {}".format(PHP5_SOCKETS_PREFIX, PHP7_SOCKETS_PREFIX, f) - os.system(c) + # Reload nginx + _run_service_command("reload", "nginx") + except Exception: - # Reload nginx - _run_service_command("reload", "nginx") + # Get list of php7 pool files + php7_pool_files = glob.glob("{}/*.conf".format(PHP7_POOLS)) - def backward(self): + # Keep only files which have the migration comment + php7_pool_files = [f for f in php7_pool_files if open(f).readline().strip() == MIGRATION_COMMENT] - # Get list of php7 pool files - php7_pool_files = glob.glob("{}/*.conf".format(PHP7_POOLS)) + # Delete those files + for f in php7_pool_files: + os.remove(f) - # Keep only files which have the migration comment - php7_pool_files = [f for f in php7_pool_files if open(f).readline().strip() == MIGRATION_COMMENT] + # Reload/restart the php pools + _run_service_command("stop", "php7.0-fpm") + os.system("systemctl start php5-fpm") - # Delete those files - for f in php7_pool_files: - os.remove(f) + # Get list of nginx conf file + nginx_conf_files = glob.glob("/etc/nginx/conf.d/*.d/*.conf") + for f in nginx_conf_files: + # Replace the socket prefix if it's found + c = "sed -i -e 's@{}@{}@g' {}".format(PHP7_SOCKETS_PREFIX, PHP5_SOCKETS_PREFIX, f) + os.system(c) - # Reload/restart the php pools - _run_service_command("stop", "php7.0-fpm") - os.system("systemctl start php5-fpm") - - # Get list of nginx conf file - nginx_conf_files = glob.glob("/etc/nginx/conf.d/*.d/*.conf") - for f in nginx_conf_files: - # Replace the socket prefix if it's found - c = "sed -i -e 's@{}@{}@g' {}".format(PHP7_SOCKETS_PREFIX, PHP5_SOCKETS_PREFIX, f) - os.system(c) - - # Reload nginx - _run_service_command("reload", "nginx") + # Reload nginx + _run_service_command("reload", "nginx") + raise diff --git a/src/yunohost/data_migrations/0005_postgresql_9p4_to_9p6.py b/src/yunohost/data_migrations/0005_postgresql_9p4_to_9p6.py index 9cb6e51bd..3127f2c65 100644 --- a/src/yunohost/data_migrations/0005_postgresql_9p4_to_9p6.py +++ b/src/yunohost/data_migrations/0005_postgresql_9p4_to_9p6.py @@ -16,7 +16,7 @@ class MyMigration(Migration): dependencies = ["migrate_to_stretch"] - def forward(self): + def run(self): if not self.package_is_installed("postgresql-9.4"): logger.warning(m18n.n("migration_0005_postgresql_94_not_installed")) diff --git a/src/yunohost/data_migrations/0006_sync_admin_and_root_passwords.py b/src/yunohost/data_migrations/0006_sync_admin_and_root_passwords.py index 953652111..844e3028c 100644 --- a/src/yunohost/data_migrations/0006_sync_admin_and_root_passwords.py +++ b/src/yunohost/data_migrations/0006_sync_admin_and_root_passwords.py @@ -20,7 +20,7 @@ class MyMigration(Migration): "Synchronize admin and root passwords" - def forward(self): + def run(self): new_hash = self._get_admin_hash() self._replace_root_hash(new_hash) diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py index 7ddcec7fd..99eb90b19 100644 --- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py +++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py @@ -34,7 +34,7 @@ class MyMigration(Migration): use the recommended configuration, with an appropriate disclaimer. """ - def forward(self): + def run(self): # Check if deprecated DSA Host Key is in config dsa_rgx = r'^[ \t]*HostKey[ \t]+/etc/ssh/ssh_host_dsa_key[ \t]*(?:#.*)?$' @@ -55,19 +55,13 @@ class MyMigration(Migration): # right after the regenconf, such that it will appear as # "manually modified". if os.path.exists('/etc/yunohost/from_script'): - rm('/etc/yunohost/from_script') - copyfile(SSHD_CONF, '/etc/ssh/sshd_config.bkp') - regen_conf(names=['ssh'], force=True) - copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) - - # Restart ssh and backward if it fail - if not _run_service_command('restart', 'ssh'): - self.backward() - raise YunohostError("migration_0007_cancel") - - def backward(self): - - # We don't backward completely but it should be enough - copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) - if not _run_service_command('restart', 'ssh'): - raise YunohostError("migration_0007_cannot_restart") + try: + rm('/etc/yunohost/from_script') + copyfile(SSHD_CONF, '/etc/ssh/sshd_config.bkp') + regen_conf(names=['ssh'], force=True) + copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) + except Exception: + if os.path.exists('/etc/yunohost/sshd_config.bkp'): + copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) + _run_service_command('restart', 'ssh') + raise diff --git a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py index c158192f9..ecc8cfdcb 100644 --- a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py +++ b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py @@ -35,7 +35,7 @@ class MyMigration(Migration): dependencies = ["ssh_conf_managed_by_yunohost_step1"] - def forward(self): + def run(self): settings_set("service.ssh.allow_deprecated_dsa_hostkey", False) regen_conf(names=['ssh'], force=True) diff --git a/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py b/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py index ffe2279a8..c190e2aaa 100644 --- a/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py +++ b/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py @@ -17,7 +17,7 @@ class MyMigration(Migration): Decouple the regen conf mechanism from the concept of services """ - def forward(self): + def run(self): if "conffiles" not in read_file("/etc/yunohost/services.yml") \ or os.path.exists(REGEN_CONF_FILE): diff --git a/src/yunohost/data_migrations/0010_migrate_to_apps_json.py b/src/yunohost/data_migrations/0010_migrate_to_apps_json.py index 7092d92c7..fbcec5117 100644 --- a/src/yunohost/data_migrations/0010_migrate_to_apps_json.py +++ b/src/yunohost/data_migrations/0010_migrate_to_apps_json.py @@ -15,7 +15,7 @@ class MyMigration(Migration): "Migrate from official.json to apps.json" - def forward(self): + def run(self): # Backup current app list json os.system("cp %s %s" % (APPSLISTS_JSON, APPSLISTS_BACKUP)) @@ -28,17 +28,21 @@ class MyMigration(Migration): "labriqueinter.net/apps/labriqueinternet.json", "labriqueinter.net/internetcube.json" ] + try: + appslists = _read_appslist_list() + for appslist, infos in appslists.items(): + if infos["url"].split("//")[-1] in lists_to_remove: + app_removelist(name=appslist) - appslists = _read_appslist_list() - for appslist, infos in appslists.items(): - if infos["url"].split("//")[-1] in lists_to_remove: - app_removelist(name=appslist) + # Replace by apps.json list + app_fetchlist(name="yunohost", + url="https://app.yunohost.org/apps.json") + except Exception: + if os.path.exists(APPSLISTS_BACKUP): + os.system("cp %s %s" % (APPSLISTS_BACKUP, APPSLISTS_JSON)) + raise + else: + if os.path.exists(APPSLISTS_BACKUP): + os.remove(APPSLISTS_BACKUP) - # Replace by apps.json list - app_fetchlist(name="yunohost", - url="https://app.yunohost.org/apps.json") - def backward(self): - - if os.path.exists(APPSLISTS_BACKUP): - os.system("cp %s %s" % (APPSLISTS_BACKUP, APPSLISTS_JSON)) diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index 0e371944e..17fd8f4a5 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -92,7 +92,7 @@ class MyMigration(Migration): app_setting(app, 'allowed_users', delete=True) - def forward(self): + def run(self): # Check if the migration can be processed ldap_regen_conf_status = regen_conf(names=['slapd'], dry_run=True) # By this we check if the have been customized diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index d84ca3199..1c185e90c 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -1038,7 +1038,7 @@ def tools_migrations_list(pending=False, done=False): return {"migrations": migrations} -def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=False, revert=False, accept_disclaimer=False): +def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=False, accept_disclaimer=False): """ Perform migrations @@ -1046,7 +1046,6 @@ def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=Fal --skip Skip specified migrations (to be used only if you know what you are doing) (must explicit which migrations) --auto Automatic mode, won't run manual migrations (to be used only if you know what you are doing) --force-rerun Re-run already-ran migrations (to be used only if you know what you are doing)(must explicit which migrations) - --revert Attempt to revert already-ran migrations (to be used only if you know what you are doing)(must explicit which migrations) --accept-disclaimer Accept disclaimers of migrations (please read them before using this option) (only valid for one migration) """ @@ -1060,14 +1059,14 @@ def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=Fal raise YunohostError("migrations_no_such_migration", id=target) - # auto, skip, revert and force are exclusive options - if auto + skip + revert + force_rerun > 1: + # auto, skip and force are exclusive options + if auto + skip + force_rerun > 1: raise YunohostError("migrations_exclusive_options") # If no target specified if not targets: # skip, revert or force require explicit targets - if (skip or revert or force_rerun): + if (skip or force_rerun): raise YunohostError("migrations_must_provide_explicit_targets") # Otherwise, targets are all pending migrations @@ -1081,9 +1080,9 @@ def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=Fal if skip and done: raise YunohostError("migrations_not_pending_cant_skip", ids=', '.join(done)) - if (revert or force_rerun) and pending: + if force_rerun and pending: raise YunohostError("migrations_pending_cant_revert_or_rerun", ids=', '.join(pending)) - if not (skip or revert or force_rerun) and done: + if not (skip or force_rerun) and done: raise YunohostError("migrations_already_ran", ids=', '.join(done)) # So, is there actually something to do ? @@ -1105,7 +1104,7 @@ def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=Fal continue # Check for migration dependencies - if not revert and not skip: + if not skip: dependencies = [get_matching_migration(dep) for dep in migration.dependencies] pending_dependencies = [dep.id for dep in dependencies if dep.state == "pending"] if pending_dependencies: @@ -1115,7 +1114,7 @@ def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=Fal continue # If some migrations have disclaimers (and we're not trying to skip them) - if migration.disclaimer and not skip and not revert: + if migration.disclaimer and not skip: # require the --accept-disclaimer option. # Otherwise, go to the next migration if not accept_disclaimer: @@ -1128,8 +1127,7 @@ def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=Fal accept_disclaimer = False # Start register change on system - mode = "backward" if revert else "forward" - operation_logger = OperationLogger('tools_migrations_migrate_' + mode) + operation_logger = OperationLogger('tools_migrations_migrate_forward') operation_logger.start() if skip: @@ -1141,12 +1139,8 @@ def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=Fal try: migration.operation_logger = operation_logger - if revert: - logger.info(m18n.n('migrations_running_backward', id=migration.id)) - migration.backward() - else: logger.info(m18n.n('migrations_running_forward', id=migration.id)) - migration.migrate() + migration.run() except Exception as e: # migration failed, let's stop here but still update state because # we managed to run the previous ones @@ -1155,14 +1149,9 @@ def tools_migrations_migrate(targets=[], skip=False, auto=False, force_rerun=Fal logger.error(msg, exc_info=1) operation_logger.error(msg) else: - if revert: - logger.success(m18n.n('migrations_success_revert', id=migration.id)) - migration.state = "pending" - _write_migration_state(migration.id, "pending") - else: - logger.success(m18n.n('migrations_success_forward', id=migration.id)) - migration.state = "done" - _write_migration_state(migration.id, "done") + logger.success(m18n.n('migrations_success_forward', id=migration.id)) + migration.state = "done" + _write_migration_state(migration.id, "done") operation_logger.success() @@ -1304,6 +1293,9 @@ def _skip_all_migrations(): write_to_yaml(MIGRATIONS_STATE_PATH, new_states) +def _get_revert_dependencies(migration, all_migrations): + + class Migration(object): # Those are to be implemented by daughter classes @@ -1311,20 +1303,14 @@ class Migration(object): mode = "auto" dependencies = [] # List of migration ids required before running this migration - def forward(self): - raise NotImplementedError() - - def backward(self): - raise YunohostError("migration_backward_impossible", name=self.name) - @property def disclaimer(self): return None # The followings shouldn't be overriden - def migrate(self): - self.forward() + def run(self): + raise NotImplementedError() def __init__(self, id_): self.id = id_