Repository: learningequality/kolibri

Issue:
Migrations / Initialization happens without checking if another instance is running
### Observed behavior

Kolibri 0.13.0.dev runs migrations even though another instance is running, which can potentially lead to database corruption.

CC: @rtibbles 

### Expected behavior

Kolibri should immediately quit.

### User-facing consequences

Almost certainly bad.

### Errors and logs

```
➜  kolibri git:(develop) kolibri start --foreground          
WARNING:root:No C Extensions available for this platform.

INFO     Option RUN_MODE in section [Deployment] being overridden by environment variable KOLIBRI_RUN_MODE
INFO     Running Kolibri with the following settings: kolibri.deployment.default.settings.base
INFO     Version was 0.13.0.dev0+git.20190716150511, new version: 0.13.0.dev0+git.20190822215051
INFO     Running update routines for new version...
Operations to perform:
  Apply all migrations: admin, analytics, auth, content, contenttypes, device, discovery, exams, kolibriauth, lessons, logger, morango, notifications, sessions
Running migrations:
  Applying content.0019_contentnode_slideshow_options... OK
  Applying morango.0013_auto_20190627_1513... OK
Operations to perform:
  Apply all migrations: admin, analytics, auth, content, contenttypes, device, discovery, exams, kolibriauth, lessons, logger, morango, notifications, sessions
Running migrations:
  Applying content.0019_contentnode_slideshow_options... OK
  Applying morango.0013_auto_20190627_1513... OK
Installed 2 object(s) from 1 fixture(s)
INFO     Sqlite database Vacuum finished.
INFO     Running Kolibri
ERROR    Port 8080 is occupied.
Please check that you do not have other processes running on this port and try again.
```

### Steps to reproduce

Run Kolibri 0.12, so it shares directory with current `develop`. Then run `kolibri start --foreground`.

### Context

Development env. for current `develop` branch on a system with 0.12.8 installed from .deb.

### Related

The otherwise great #5494 


Discussion:
Sounds good - just need to run the sanity check before we do the update logic, yes?
Agreed, but aren't sanity checks already run when `kolibri start` is run?
Yes - but the update is run before the sanity checks currently.
Oh interesting: Not having run updates isn't sane, but system should be sane before running them... this is a Catch 22 :)

Should we split something up here or will it be safe to run sanity checks before migrations/upgrading?
I think it's fine to run them before - they used to be run at module import, so it's just a matter of reinstating that order (but not having to run them at module import).

Resolving patch:
diff --git a/kolibri/utils/cli.py b/kolibri/utils/cli.py
--- a/kolibri/utils/cli.py
+++ b/kolibri/utils/cli.py
@@ -334,6 +334,20 @@ def update(old_version, new_version):
 
     logger.info("Running update routines for new version...")
 
+    try:
+        # Check if there are other kolibri instances running
+        # If there are, then we need to stop users from starting kolibri again.
+        server.get_status()
+        logger.error(
+            "There is a Kolibri server running."
+            "Running updates now could cause a database error."
+            "Please use `kolibri stop` and try again."
+        )
+        sys.exit(1)
+
+    except server.NotRunning:
+        pass
+
     # Need to do this here, before we run any Django management commands that
     # import settings. Otherwise the updated configuration will not be used
     # during this runtime.


Test patch:
diff --git a/kolibri/utils/tests/test_cli.py b/kolibri/utils/tests/test_cli.py
--- a/kolibri/utils/tests/test_cli.py
+++ b/kolibri/utils/tests/test_cli.py
@@ -228,6 +228,20 @@ def test_update(update, get_version):
     update.assert_called_once()
 
 
+@pytest.mark.django_db
+@patch("kolibri.utils.cli.get_version", return_value="0.0.1")
+def test_update_exits_if_running(get_version):
+    """
+    Tests that update() function performs as expected
+    """
+    with patch("kolibri.utils.cli.server.get_status"):
+        try:
+            cli.initialize()
+            pytest.fail("Update did not exit when Kolibri was already running")
+        except SystemExit:
+            pass
+
+
 @pytest.mark.django_db
 def test_version_updated():
     """