From 0c61c1abb59eed6d92fba5e396ed3e3e6360fc33 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Tue, 11 Jan 2022 08:36:11 +0300 Subject: [PATCH] Migrations mechanism and fix to the nixos-config branch --- selfprivacy_api/app.py | 5 ++- selfprivacy_api/migrations/__init__.py | 24 +++++++++++ .../migrations/fix_nixos_config_branch.py | 41 +++++++++++++++++++ selfprivacy_api/migrations/migration.py | 26 ++++++++++++ selfprivacy_api/resources/common.py | 2 +- 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 selfprivacy_api/migrations/__init__.py create mode 100644 selfprivacy_api/migrations/fix_nixos_config_branch.py create mode 100644 selfprivacy_api/migrations/migration.py diff --git a/selfprivacy_api/app.py b/selfprivacy_api/app.py index fc04aeb..3b575db 100644 --- a/selfprivacy_api/app.py +++ b/selfprivacy_api/app.py @@ -16,6 +16,8 @@ from selfprivacy_api.resources.services import services as api_services from selfprivacy_api.restic_controller.tasks import huey, init_restic +from selfprivacy_api.migrations import run_migrations + swagger_blueprint = get_swaggerui_blueprint( "/api/docs", "/api/swagger.json", config={"app_name": "SelfPrivacy API"} ) @@ -59,7 +61,7 @@ def create_app(test_config=None): def spec(): if app.config["ENABLE_SWAGGER"] == "1": swag = swagger(app) - swag["info"]["version"] = "1.1.0" + swag["info"]["version"] = "1.1.1" swag["info"]["title"] = "SelfPrivacy API" swag["info"]["description"] = "SelfPrivacy API" swag["securityDefinitions"] = { @@ -83,6 +85,7 @@ def create_app(test_config=None): if __name__ == "__main__": monkey.patch_all() created_app = create_app() + run_migrations() huey.start() init_restic() created_app.run(port=5050, debug=False) diff --git a/selfprivacy_api/migrations/__init__.py b/selfprivacy_api/migrations/__init__.py new file mode 100644 index 0000000..6a7723c --- /dev/null +++ b/selfprivacy_api/migrations/__init__.py @@ -0,0 +1,24 @@ +from selfprivacy_api.utils import ReadUserData +from selfprivacy_api.migrations.fix_nixos_config_branch import FixNixosConfigBranch + +migrations = [ + FixNixosConfigBranch() +] + +def run_migrations(): + """ + Go over all migrations. If they are not skipped in userdata file, run them + if the migration needed. + """ + with ReadUserData() as data: + if "api" not in data: + skipped_migrations = [] + elif "skippedMigrations" not in data["api"]: + skipped_migrations = [] + else: + skipped_migrations = data["api"].get("skippedMigrations", []) + + for migration in migrations: + if migration.get_migration_name() not in skipped_migrations: + if migration.is_migration_needed(): + migration.migrate() diff --git a/selfprivacy_api/migrations/fix_nixos_config_branch.py b/selfprivacy_api/migrations/fix_nixos_config_branch.py new file mode 100644 index 0000000..af36c67 --- /dev/null +++ b/selfprivacy_api/migrations/fix_nixos_config_branch.py @@ -0,0 +1,41 @@ +import os +import subprocess + +from selfprivacy_api.migrations.migration import Migration + +class FixNixosConfigBranch(Migration): + def get_migration_name(self): + return "fix_nixos_config_branch" + + def get_migration_description(self): + return """Mobile SelfPrivacy app introduced a bug in version 0.4.0. + New servers were initialized with a rolling-testing nixos config branch. + This was fixed in app version 0.4.2, but existing servers were not updated. + This migration fixes this by changing the nixos config branch to master. + """ + + def is_migration_needed(self): + """Check the current branch of /etc/nixos and return True if it is rolling-testing""" + nixos_config_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], start_new_session=True) + if nixos_config_branch.decode("utf-8").strip() == "rolling-testing": + return True + else: + return False + + + def migrate(self): + """Affected server pulled the config with the --single-branch flag. + Git config remote.origin.fetch has to be changed, so all branches will be fetched. + Then, fetch all branches, pull and switch to master branch. + """ + print("Fixing Nixos config branch") + current_working_directory = os.getcwd() + os.chdir("/etc/nixos") + + subprocess.check_output(["git", "config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*"]) + subprocess.check_output(["git", "fetch", "--all"]) + subprocess.check_output(["git", "pull"]) + subprocess.check_output(["git", "checkout", "master"]) + + os.chdir(current_working_directory) + print("Done") \ No newline at end of file diff --git a/selfprivacy_api/migrations/migration.py b/selfprivacy_api/migrations/migration.py new file mode 100644 index 0000000..e5a37db --- /dev/null +++ b/selfprivacy_api/migrations/migration.py @@ -0,0 +1,26 @@ +from abc import ABC, abstractmethod + +""" +Abstract Migration class +This class is used to define the structure of a migration +Migration has a function is_migration_needed() that returns True or False +Migration has a function migrate() that does the migration +Migration has a function get_migration_name() that returns the migration name +Migration has a function get_migration_description() that returns the migration description +""" +class Migration(ABC): + @abstractmethod + def get_migration_name(self): + pass + + @abstractmethod + def get_migration_description(self): + pass + + @abstractmethod + def is_migration_needed(self): + pass + + @abstractmethod + def migrate(self): + pass diff --git a/selfprivacy_api/resources/common.py b/selfprivacy_api/resources/common.py index ba7412c..d771372 100644 --- a/selfprivacy_api/resources/common.py +++ b/selfprivacy_api/resources/common.py @@ -24,4 +24,4 @@ class ApiVersion(Resource): 401: description: Unauthorized """ - return {"version": "1.1.0"} + return {"version": "1.1.1"}