From 020dea653190afc16f928e063c354511823fbaf4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Feb 2018 01:42:33 +0100 Subject: [PATCH 01/12] Change the way we list migrations (always load the module) and the way we manage its infos --- locales/en.json | 4 +-- src/yunohost/tools.py | 59 +++++++++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/locales/en.json b/locales/en.json index 66fa93f4..f5f706d6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -226,9 +226,9 @@ "migrations_bad_value_for_target": "Invalide number for target argument, available migrations numbers are 0 or {}", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s", "migrations_current_target": "Migration target is {}", - "migrations_error_failed_to_load_migration": "ERROR: failed to load migration {number} {name}", + "migrations_error_failed_to_load_migration": "ERROR: failed to load migration {migration_id}", "migrations_forward": "Migrating forward", - "migrations_loading_migration": "Loading migration {number} {name}...", + "migrations_loading_migration": "Loading migration {migration_id}...", "migrations_migration_has_failed": "Migration {number} {name} has failed with exception {exception}, aborting", "migrations_no_migrations_to_run": "No migrations to run", "migrations_show_currently_running_migration": "Running migration {number} {name}...", diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index f98d48fc..fcea5ffb 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -741,11 +741,7 @@ def tools_migrations_list(): migrations = {"migrations": []} for migration in _get_migrations_list(): - migrations["migrations"].append({ - "number": int(migration.split("_", 1)[0]), - "name": migration.split("_", 1)[1], - "file_name": migration, - }) + migrations["migrations"].append(migration.infos()) return migrations @@ -905,55 +901,57 @@ def _get_migrations_list(): logger.warn(m18n.n('migrations_cant_reach_migration_file', migrations_path)) return migrations - for migration in filter(lambda x: re.match("^\d+_[a-zA-Z0-9_]+\.py$", x), os.listdir(migrations_path)): - migrations.append(migration[:-len(".py")]) + for migration_file in filter(lambda x: re.match("^\d+_[a-zA-Z0-9_]+\.py$", x), os.listdir(migrations_path)): + migrations.append(_load_migration(migration_file)) - return sorted(migrations) + return sorted(migrations, key=lambda m: m.id) -def _get_migration_by_name(migration_name, with_module=True): +def _get_migration_by_name(migration_name): """ Low-level / "private" function to find a migration by its name """ - migrations = tools_migrations_list()["migrations"] + try: + import data_migrations + except ImportError: + raise AssertionError("Unable to find migration with name %s" % migration_name) - matches = [ m for m in migrations if m["name"] == migration_name ] + migrations_path = data_migrations.__path__[0] + migrations_found = filter(lambda x: re.match("^\d+_%s\.py$" % migration_name, x), os.listdir(migrations_path)) - assert len(matches) == 1, "Unable to find migration with name %s" % migration_name + assert len(migrations_found) == 1, "Unable to find migration with name %s" % migration_name - migration = matches[0] - - if with_module: - migration["module"] = _get_migration_module(migration) - - return migration + return _load_migration(migrations_found[0]) -def _get_migration_module(migration): +def _load_migration(migration_file): + + migration_id = migration_file[:-len(".py")] logger.debug(m18n.n('migrations_loading_migration', - number=migration["number"], - name=migration["name"], + migration_id=migration_id, )) try: # this is python builtin method to import a module using a name, we # use that to import the migration as a python object so we'll be # able to run it in the next loop - return import_module("yunohost.data_migrations.{file_name}".format(**migration)) + module = import_module("yunohost.data_migrations.{}".format(migration_id)) + return module.MyMigration(migration_id) except Exception: import traceback traceback.print_exc() raise MoulinetteError(errno.EINVAL, m18n.n('migrations_error_failed_to_load_migration', - number=migration["number"], - name=migration["name"], + migration_id=migration_id, )) class Migration(object): + # forward() and backward() are to be implemented by daughter classes + def migrate(self): self.forward() @@ -962,3 +960,16 @@ class Migration(object): def backward(self): pass + + # The followings shouldn't be overriden + + def __init__(self, id_): + self.id = id_ + + def infos(self): + + return { + "id": self.id, + "number": int(self.id.split("_", 1)[0]), + "name": self.id.split("_", 1)[1], + } From 7f359e363b1bbced3984d13230c49f315857ba77 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Feb 2018 02:59:03 +0100 Subject: [PATCH 02/12] Add mode, description and optionnal disclaimer for migrations --- locales/en.json | 2 ++ src/yunohost/tools.py | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/locales/en.json b/locales/en.json index f5f706d6..49376a1e 100644 --- a/locales/en.json +++ b/locales/en.json @@ -222,6 +222,8 @@ "migrate_tsig_wait_3": "1min...", "migrate_tsig_wait_4": "30 secondes...", "migrate_tsig_not_needed": "You do not appear to use a dyndns domain, so no migration is needed !", + "migration_description_0001_change_cert_group_to_sslcert": "Change certificates group permissions from 'metronome' to 'ssl-cert'", + "migration_description_0002_migrate_to_tsig_sha256": "Improve security of dyndns TSIG by using SHA512 instead of MD5", "migrations_backward": "Migrating backward.", "migrations_bad_value_for_target": "Invalide number for target argument, available migrations numbers are 0 or {}", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s", diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index fcea5ffb..f0e0315c 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -950,10 +950,9 @@ def _load_migration(migration_file): class Migration(object): - # forward() and backward() are to be implemented by daughter classes + # Those are to be implemented by daughter classes - def migrate(self): - self.forward() + mode = "auto" def forward(self): raise NotImplementedError() @@ -961,15 +960,27 @@ class Migration(object): def backward(self): pass + def disclaimer(self): + return None + # The followings shouldn't be overriden + def migrate(self): + self.forward() + def __init__(self, id_): self.id = id_ + def description(self): + return m18n.n("migration_description_%s" % self.id) + def infos(self): return { "id": self.id, "number": int(self.id.split("_", 1)[0]), "name": self.id.split("_", 1)[1], + "mode": self.mode, + "description": self.description(), + "disclaimer": self.disclaimer() } From 0702af6054e386fae499cf955bd55a65b2f467f1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Feb 2018 17:08:52 +0100 Subject: [PATCH 03/12] Simplify my previous stuff about managing migration infos ? --- src/yunohost/tools.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index f0e0315c..10735946 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -741,7 +741,14 @@ def tools_migrations_list(): migrations = {"migrations": []} for migration in _get_migrations_list(): - migrations["migrations"].append(migration.infos()) + migrations["migrations"].append({ + "id": migration.id, + "number": migration.number, + "name": migration.name, + "mode": migration.mode, + "description": migration.description, + "disclaimer": migration.disclaimer + }) return migrations @@ -960,6 +967,7 @@ class Migration(object): def backward(self): pass + @property def disclaimer(self): return None @@ -970,17 +978,9 @@ class Migration(object): def __init__(self, id_): self.id = id_ + self.number = int(self.id.split("_", 1)[0]) + self.name = self.id.split("_", 1)[1] + @property def description(self): return m18n.n("migration_description_%s" % self.id) - - def infos(self): - - return { - "id": self.id, - "number": int(self.id.split("_", 1)[0]), - "name": self.id.split("_", 1)[1], - "mode": self.mode, - "description": self.description(), - "disclaimer": self.disclaimer() - } From d73197793c37fc8c45d21569be9265b67f01ef5a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Feb 2018 17:44:25 +0100 Subject: [PATCH 04/12] Adapt migrations_migrate according to previous changes --- src/yunohost/tools.py | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 10735946..1e49d1f0 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -770,26 +770,18 @@ def tools_migrations_migrate(target=None, skip=False): last_run_migration_number = state["last_run_migration"]["number"] if state["last_run_migration"] else 0 - migrations = [] - - # loading all migrations - for migration in tools_migrations_list()["migrations"]: - migrations.append({ - "number": migration["number"], - "name": migration["name"], - "module": _get_migration_module(migration), - }) - - migrations = sorted(migrations, key=lambda x: x["number"]) + # load all migrations + migrations = _get_migrations_list() + migrations = sorted(migrations, key=lambda x: x.number) if not migrations: logger.info(m18n.n('migrations_no_migrations_to_run')) return - all_migration_numbers = [x["number"] for x in migrations] + all_migration_numbers = [x.number for x in migrations] if target is None: - target = migrations[-1]["number"] + target = migrations[-1].number # validate input, target must be "0" or a valid number elif target != 0 and target not in all_migration_numbers: @@ -808,14 +800,14 @@ def tools_migrations_migrate(target=None, skip=False): if last_run_migration_number < target: logger.debug(m18n.n('migrations_forward')) # drop all already run migrations - migrations = filter(lambda x: target >= x["number"] > last_run_migration_number, migrations) + migrations = filter(lambda x: target >= x.number > last_run_migration_number, migrations) mode = "forward" # we need to go backward on already run migrations elif last_run_migration_number > target: logger.debug(m18n.n('migrations_backward')) # drop all not already run migrations - migrations = filter(lambda x: target < x["number"] <= last_run_migration_number, migrations) + migrations = filter(lambda x: target < x.number <= last_run_migration_number, migrations) mode = "backward" else: # can't happen, this case is handle before @@ -824,19 +816,24 @@ def tools_migrations_migrate(target=None, skip=False): # effectively run selected migrations for migration in migrations: if not skip: - logger.warn(m18n.n('migrations_show_currently_running_migration', **migration)) + logger.warn(m18n.n('migrations_show_currently_running_migration', + number=migration.number, name=migration.name)) try: if mode == "forward": - migration["module"].MyMigration().migrate() + migration.migrate() elif mode == "backward": - migration["module"].MyMigration().backward() + migration.backward() else: # can't happen raise Exception("Illegal state for migration: '%s', should be either 'forward' or 'backward'" % mode) except Exception as e: # migration failed, let's stop here but still update state because # we managed to run the previous ones - logger.error(m18n.n('migrations_migration_has_failed', exception=e, **migration), exc_info=1) + logger.error(m18n.n('migrations_migration_has_failed', + exception=e, + number=migration.number, + name=migration.name), + exc_info=1) break else: # if skip @@ -844,8 +841,8 @@ def tools_migrations_migrate(target=None, skip=False): # update the state to include the latest run migration state["last_run_migration"] = { - "number": migration["number"], - "name": migration["name"], + "number": migration.number, + "name": migration.name } # special case where we want to go back from the start From bafe6efde2f3b93523b4702facaf36b24d841ed3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Feb 2018 17:45:03 +0100 Subject: [PATCH 05/12] Typo --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 49376a1e..4828c6f2 100644 --- a/locales/en.json +++ b/locales/en.json @@ -225,7 +225,7 @@ "migration_description_0001_change_cert_group_to_sslcert": "Change certificates group permissions from 'metronome' to 'ssl-cert'", "migration_description_0002_migrate_to_tsig_sha256": "Improve security of dyndns TSIG by using SHA512 instead of MD5", "migrations_backward": "Migrating backward.", - "migrations_bad_value_for_target": "Invalide number for target argument, available migrations numbers are 0 or {}", + "migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s", "migrations_current_target": "Migration target is {}", "migrations_error_failed_to_load_migration": "ERROR: failed to load migration {migration_id}", From c40f14e8f0a21e5ec663ba4bd8358899ed5cf921 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Feb 2018 17:49:46 +0100 Subject: [PATCH 06/12] Adapt 'manual' call to migration from dyndns according to previous changes --- src/yunohost/dyndns.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/yunohost/dyndns.py b/src/yunohost/dyndns.py index ec3bf88c..60bea90e 100644 --- a/src/yunohost/dyndns.py +++ b/src/yunohost/dyndns.py @@ -232,10 +232,13 @@ def dyndns_update(dyn_host="dyndns.yunohost.org", domain=None, key=None, from yunohost.tools import _get_migration_by_name migration = _get_migration_by_name("migrate_to_tsig_sha256") try: - migration["module"].MyMigration().migrate(dyn_host, domain, key) + migration.migrate(dyn_host, domain, key) except Exception as e: - logger.error(m18n.n('migrations_migration_has_failed', exception=e, **migration), exc_info=1) - + logger.error(m18n.n('migrations_migration_has_failed', + exception=e, + number=migration.number, + name=migration.name), + exc_info=1) return # Extract 'host', e.g. 'nohost.me' from 'foo.nohost.me' From c568b04459422bea7d0e8a92a2b33bbfedec7ac3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Feb 2018 21:11:12 +0100 Subject: [PATCH 07/12] Manage the auto/manual flag in migrations_migrate --- data/actionsmap/yunohost.yml | 3 +++ debian/postinst | 2 +- locales/en.json | 1 + src/yunohost/tools.py | 16 +++++++++++++--- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 77887b41..d84d308c 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1589,6 +1589,9 @@ tools: help: skip the migration(s), use it only if you know what you are doing full: --skip action: store_true + --auto: + help: automatic mode, won't run manual migrations, use it only if you know what you are doing + action: store_true ### tools_migrations_state() diff --git a/debian/postinst b/debian/postinst index 7e91ffbb..5b6ed825 100644 --- a/debian/postinst +++ b/debian/postinst @@ -15,7 +15,7 @@ do_configure() { yunohost service regen-conf --output-as none echo "Launching migrations.." - yunohost tools migrations migrate + yunohost tools migrations migrate --auto # restart yunohost-firewall if it's running service yunohost-firewall status >/dev/null \ diff --git a/locales/en.json b/locales/en.json index 4828c6f2..7597e17e 100644 --- a/locales/en.json +++ b/locales/en.json @@ -236,6 +236,7 @@ "migrations_show_currently_running_migration": "Running migration {number} {name}...", "migrations_show_last_migration": "Last ran migration is {}", "migrations_skip_migration": "Skipping migration {number} {name}...", + "migrations_to_be_ran_manually": "Migration {number} {name} has to be ran manually. Please go to Tools > Migrations on the webadmin, or run `yunohost tools migrations migrate`.", "monitor_disabled": "The server monitoring has been disabled", "monitor_enabled": "The server monitoring has been enabled", "monitor_glances_con_failed": "Unable to connect to Glances server", diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 1e49d1f0..0e2e1195 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -753,7 +753,7 @@ def tools_migrations_list(): return migrations -def tools_migrations_migrate(target=None, skip=False): +def tools_migrations_migrate(target=None, skip=False, auto=False): """ Perform migrations """ @@ -816,8 +816,18 @@ def tools_migrations_migrate(target=None, skip=False): # effectively run selected migrations for migration in migrations: if not skip: - logger.warn(m18n.n('migrations_show_currently_running_migration', - number=migration.number, name=migration.name)) + + # If we are migrating in "automatic mode" (i.e. from debian + # configure during an upgrade of the package) but the migration + # is to be ran manually by the user + if auto and migration.mode == "manual": + logger.warn(m18n.n('migrations_to_be_ran_manually', + number=migration.number, name=migration.name)) + break + else: + logger.warn(m18n.n('migrations_show_currently_running_migration', + number=migration.number, name=migration.name)) + try: if mode == "forward": From c266147fd9ce4654c6b0b0766aa45eff21c4a71d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 3 Feb 2018 03:27:13 +0100 Subject: [PATCH 08/12] Be able to list only pending or done migrations --- data/actionsmap/yunohost.yml | 7 +++++++ locales/en.json | 1 + src/yunohost/tools.py | 36 ++++++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index d84d308c..8eba4530 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1575,6 +1575,13 @@ tools: list: action_help: List migrations api: GET /migrations + arguments: + --pending: + help: list only pending migrations + action: store_true + --done: + help: list only migrations already performed + action: store_true ### tools_migrations_migrate() migrate: diff --git a/locales/en.json b/locales/en.json index 7597e17e..e5034cf8 100644 --- a/locales/en.json +++ b/locales/en.json @@ -230,6 +230,7 @@ "migrations_current_target": "Migration target is {}", "migrations_error_failed_to_load_migration": "ERROR: failed to load migration {migration_id}", "migrations_forward": "Migrating forward", + "migrations_list_conflict_pending_done": "You cannot use both --previous and --done at the same time.", "migrations_loading_migration": "Loading migration {migration_id}...", "migrations_migration_has_failed": "Migration {number} {name} has failed with exception {exception}, aborting", "migrations_no_migrations_to_run": "No migrations to run", diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 0e2e1195..0978956f 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -733,24 +733,36 @@ def tools_reboot(force=False): subprocess.check_call(['systemctl', 'reboot']) -def tools_migrations_list(): +def tools_migrations_list(pending=False, done=False): """ List existing migrations """ - migrations = {"migrations": []} + # Check for option conflict + if pending and done: + raise MoulinetteError(errno.EINVAL, m18n.n("migrations_list_conflict_pending_done")) - for migration in _get_migrations_list(): - migrations["migrations"].append({ - "id": migration.id, - "number": migration.number, - "name": migration.name, - "mode": migration.mode, - "description": migration.description, - "disclaimer": migration.disclaimer - }) + # Get all migrations + migrations = _get_migrations_list() - return migrations + # If asked, filter pending or done migrations + if pending or done: + last_migration = tools_migrations_state()["last_run_migration"] + last_migration = last_migration["number"] if last_migration else -1 + if done: + migrations = [m for m in migrations if m.number <= last_migration] + if pending: + migrations = [m for m in migrations if m.number > last_migration] + + # Reduce to dictionnaries + migrations = [{ "id": migration.id, + "number": migration.number, + "name": migration.name, + "mode": migration.mode, + "description": migration.description, + "disclaimer": migration.disclaimer } for migration in migrations ] + + return {"migrations": migrations} def tools_migrations_migrate(target=None, skip=False, auto=False): From c8b1d7e2c3a830d4a242a251304ed7d13f241093 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 5 Feb 2018 15:23:42 +0100 Subject: [PATCH 09/12] Forgot to adapt this also.. --- src/yunohost/tools.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 0978956f..2fd13931 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -859,7 +859,9 @@ def tools_migrations_migrate(target=None, skip=False, auto=False): break else: # if skip - logger.warn(m18n.n('migrations_skip_migration', **migration)) + logger.warn(m18n.n('migrations_skip_migration', + number=migration.number, + name=migration.name)) # update the state to include the latest run migration state["last_run_migration"] = { From 9009b3f9d35b6d2945926e0b144c553bf4af4850 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 5 Feb 2018 18:13:51 +0100 Subject: [PATCH 10/12] Handle disclaimers --- data/actionsmap/yunohost.yml | 4 +++- locales/en.json | 1 + src/yunohost/tools.py | 37 ++++++++++++++++++++++++------------ 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 8eba4530..715a1350 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1599,7 +1599,9 @@ tools: --auto: help: automatic mode, won't run manual migrations, use it only if you know what you are doing action: store_true - + --accept-disclaimer: + help: accept disclaimers of migration (please read them before using this option) + action: store_true ### tools_migrations_state() state: diff --git a/locales/en.json b/locales/en.json index e5034cf8..b0c2ea3d 100644 --- a/locales/en.json +++ b/locales/en.json @@ -238,6 +238,7 @@ "migrations_show_last_migration": "Last ran migration is {}", "migrations_skip_migration": "Skipping migration {number} {name}...", "migrations_to_be_ran_manually": "Migration {number} {name} has to be ran manually. Please go to Tools > Migrations on the webadmin, or run `yunohost tools migrations migrate`.", + "migrations_need_to_accept_disclaimer": "To run the migration {number} {name}, your must accept the following disclaimer:\n---\n{disclaimer}\n---\nIf you accept to run the migration, please re-run the command with the option --accept-disclaimer.", "monitor_disabled": "The server monitoring has been disabled", "monitor_enabled": "The server monitoring has been enabled", "monitor_glances_con_failed": "Unable to connect to Glances server", diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 2fd13931..9719f922 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -765,7 +765,7 @@ def tools_migrations_list(pending=False, done=False): return {"migrations": migrations} -def tools_migrations_migrate(target=None, skip=False, auto=False): +def tools_migrations_migrate(target=None, skip=False, auto=False, accept_disclaimer=False): """ Perform migrations """ @@ -825,21 +825,34 @@ def tools_migrations_migrate(target=None, skip=False, auto=False): else: # can't happen, this case is handle before raise Exception() + # If we are migrating in "automatic mode" (i.e. from debian + # configure during an upgrade of the package) but we are asked to run + # migrations is to be ran manually by the user + manual_migrations = [m for m in migrations if m.mode == "manual"] + if auto and manual_migrations: + for m in manual_migrations: + logger.warn(m18n.n('migrations_to_be_ran_manually', + number=m.number, + name=m.name)) + return + + # If some migrations have disclaimers, require the --accept-disclaimer + # option + migrations_with_disclaimer = [m for m in migrations if m.disclaimer] + if not accept_disclaimer and migrations_with_disclaimer: + for m in migrations_with_disclaimer: + logger.warn(m18n.n('migrations_need_to_accept_disclaimer', + number=m.number, + name=m.name, + disclaimer=m.disclaimer)) + return + # effectively run selected migrations for migration in migrations: if not skip: - # If we are migrating in "automatic mode" (i.e. from debian - # configure during an upgrade of the package) but the migration - # is to be ran manually by the user - if auto and migration.mode == "manual": - logger.warn(m18n.n('migrations_to_be_ran_manually', - number=migration.number, name=migration.name)) - break - else: - logger.warn(m18n.n('migrations_show_currently_running_migration', - number=migration.number, name=migration.name)) - + logger.warn(m18n.n('migrations_show_currently_running_migration', + number=migration.number, name=migration.name)) try: if mode == "forward": From 44a66b1ff4453d2e88aebe64a38de275a2e02844 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 5 Mar 2018 23:42:01 +0100 Subject: [PATCH 11/12] Fix migration skipping during postinstall --- src/yunohost/tools.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 9719f922..5e6e3f88 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -396,7 +396,7 @@ def tools_postinstall(domain, password, ignore_dyndns=False): _install_appslist_fetch_cron() # Init migrations (skip them, no need to run them on a fresh system) - tools_migrations_migrate(skip=True) + tools_migrations_migrate(skip=True, auto=True) os.system('touch /etc/yunohost/installed') @@ -829,7 +829,7 @@ def tools_migrations_migrate(target=None, skip=False, auto=False, accept_disclai # configure during an upgrade of the package) but we are asked to run # migrations is to be ran manually by the user manual_migrations = [m for m in migrations if m.mode == "manual"] - if auto and manual_migrations: + if not skip and auto and manual_migrations: for m in manual_migrations: logger.warn(m18n.n('migrations_to_be_ran_manually', number=m.number, @@ -839,7 +839,7 @@ def tools_migrations_migrate(target=None, skip=False, auto=False, accept_disclai # If some migrations have disclaimers, require the --accept-disclaimer # option migrations_with_disclaimer = [m for m in migrations if m.disclaimer] - if not accept_disclaimer and migrations_with_disclaimer: + if not skip and not accept_disclaimer and migrations_with_disclaimer: for m in migrations_with_disclaimer: logger.warn(m18n.n('migrations_need_to_accept_disclaimer', number=m.number, From 79eb70ec61ae35b7984e57096629a5603b0f5707 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 10 Mar 2018 16:09:16 +0100 Subject: [PATCH 12/12] Use number/name in i18n string to avoid breaking existing translations... --- locales/en.json | 4 ++-- src/yunohost/tools.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/locales/en.json b/locales/en.json index b0c2ea3d..9957c25a 100644 --- a/locales/en.json +++ b/locales/en.json @@ -228,10 +228,10 @@ "migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s", "migrations_current_target": "Migration target is {}", - "migrations_error_failed_to_load_migration": "ERROR: failed to load migration {migration_id}", + "migrations_error_failed_to_load_migration": "ERROR: failed to load migration {number} {name}", "migrations_forward": "Migrating forward", "migrations_list_conflict_pending_done": "You cannot use both --previous and --done at the same time.", - "migrations_loading_migration": "Loading migration {migration_id}...", + "migrations_loading_migration": "Loading migration {number} {name}...", "migrations_migration_has_failed": "Migration {number} {name} has failed with exception {exception}, aborting", "migrations_no_migrations_to_run": "No migrations to run", "migrations_show_currently_running_migration": "Running migration {number} {name}...", diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 5e6e3f88..c92f3bda 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -970,9 +970,10 @@ def _load_migration(migration_file): migration_id = migration_file[:-len(".py")] + number, name = migration_id.split("_", 1) + logger.debug(m18n.n('migrations_loading_migration', - migration_id=migration_id, - )) + number=number, name=name)) try: # this is python builtin method to import a module using a name, we @@ -985,8 +986,7 @@ def _load_migration(migration_file): traceback.print_exc() raise MoulinetteError(errno.EINVAL, m18n.n('migrations_error_failed_to_load_migration', - migration_id=migration_id, - )) + number=number, name=name)) class Migration(object):