mirror of
https://github.com/jupyterhub/the-littlest-jupyterhub.git
synced 2025-12-18 21:54:05 +08:00
move config migration to its own file
This commit is contained in:
@@ -2,12 +2,10 @@
|
|||||||
Unit test functions in installer.py
|
Unit test functions in installer.py
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from datetime import date
|
|
||||||
|
|
||||||
from tljh import installer
|
from tljh import installer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_ensure_node():
|
def test_ensure_node():
|
||||||
installer.ensure_node()
|
installer.ensure_node()
|
||||||
assert os.path.exists('/usr/bin/node')
|
assert os.path.exists('/usr/bin/node')
|
||||||
@@ -19,39 +17,5 @@ def test_ensure_config_yaml(tljh_dir):
|
|||||||
assert os.path.exists(installer.CONFIG_FILE)
|
assert os.path.exists(installer.CONFIG_FILE)
|
||||||
assert os.path.isdir(installer.CONFIG_DIR)
|
assert os.path.isdir(installer.CONFIG_DIR)
|
||||||
assert os.path.isdir(os.path.join(installer.CONFIG_DIR, 'jupyterhub_config.d'))
|
assert os.path.isdir(os.path.join(installer.CONFIG_DIR, 'jupyterhub_config.d'))
|
||||||
assert not os.path.exists(installer.OLD_CONFIG_FILE)
|
# verify that old config doesn't exist
|
||||||
|
assert not os.path.exists(os.path.join(tljh_dir, 'config.yaml'))
|
||||||
# run again, with old config in the way and no new config
|
|
||||||
upgraded_config = 'old: config\n'
|
|
||||||
with open(installer.OLD_CONFIG_FILE, 'w') as f:
|
|
||||||
f.write(upgraded_config)
|
|
||||||
os.remove(installer.CONFIG_FILE)
|
|
||||||
installer.ensure_config_yaml(pm)
|
|
||||||
assert os.path.exists(installer.CONFIG_FILE)
|
|
||||||
assert not os.path.exists(installer.OLD_CONFIG_FILE)
|
|
||||||
with open(installer.CONFIG_FILE) as f:
|
|
||||||
assert f.read() == upgraded_config
|
|
||||||
|
|
||||||
# run again, this time with both old and new config
|
|
||||||
duplicate_config = 'dupe: config\n'
|
|
||||||
with open(installer.OLD_CONFIG_FILE, 'w') as f:
|
|
||||||
f.write(duplicate_config)
|
|
||||||
installer.ensure_config_yaml(pm)
|
|
||||||
assert os.path.exists(installer.CONFIG_FILE)
|
|
||||||
assert not os.path.exists(installer.OLD_CONFIG_FILE)
|
|
||||||
# didn't clobber config:
|
|
||||||
with open(installer.CONFIG_FILE) as f:
|
|
||||||
assert f.read() == upgraded_config
|
|
||||||
|
|
||||||
# preserved old config
|
|
||||||
backup_config = installer.CONFIG_FILE + f".old.{date.today().isoformat()}"
|
|
||||||
assert os.path.exists(backup_config)
|
|
||||||
with open(backup_config) as f:
|
|
||||||
assert f.read() == duplicate_config
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
57
tests/test_migrator.py
Normal file
57
tests/test_migrator.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
"""
|
||||||
|
Unit test functions in installer.py
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
from tljh import migrator, config
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_config(tljh_dir):
|
||||||
|
CONFIG_FILE = config.CONFIG_FILE
|
||||||
|
CONFIG_DIR = config.CONFIG_DIR
|
||||||
|
OLD_CONFIG_FILE = os.path.join(tljh_dir, "config.yaml")
|
||||||
|
OLD_CONFIG_D = os.path.join(tljh_dir, "jupyterhub_config.d")
|
||||||
|
CONFIG_D = os.path.join(config.CONFIG_DIR, "jupyterhub_config.d")
|
||||||
|
old_config_py = os.path.join(OLD_CONFIG_D, "upgrade.py")
|
||||||
|
new_config_py = os.path.join(CONFIG_D, "upgrade.py")
|
||||||
|
|
||||||
|
# initial condition: nothing exists
|
||||||
|
assert not os.path.exists(CONFIG_FILE)
|
||||||
|
assert not os.path.exists(OLD_CONFIG_FILE)
|
||||||
|
assert os.path.isdir(CONFIG_DIR)
|
||||||
|
|
||||||
|
# run migration with old config and no new config
|
||||||
|
upgraded_config = "old: config\n"
|
||||||
|
with open(OLD_CONFIG_FILE, "w") as f:
|
||||||
|
f.write(upgraded_config)
|
||||||
|
os.makedirs(OLD_CONFIG_D, exist_ok=True)
|
||||||
|
with open(old_config_py, "w") as f:
|
||||||
|
f.write("c.JupyterHub.log_level = 10")
|
||||||
|
|
||||||
|
migrator.migrate_config_files()
|
||||||
|
assert os.path.exists(CONFIG_FILE)
|
||||||
|
assert not os.path.exists(OLD_CONFIG_FILE)
|
||||||
|
with open(CONFIG_FILE) as f:
|
||||||
|
assert f.read() == upgraded_config
|
||||||
|
assert os.path.exists(new_config_py)
|
||||||
|
assert not os.path.exists(OLD_CONFIG_D)
|
||||||
|
|
||||||
|
# run again, this time with both old and new config
|
||||||
|
duplicate_config = "dupe: config\n"
|
||||||
|
with open(OLD_CONFIG_FILE, "w") as f:
|
||||||
|
f.write(duplicate_config)
|
||||||
|
migrator.migrate_config_files()
|
||||||
|
assert os.path.exists(CONFIG_FILE)
|
||||||
|
assert not os.path.exists(OLD_CONFIG_FILE)
|
||||||
|
# didn't clobber config:
|
||||||
|
with open(CONFIG_FILE) as f:
|
||||||
|
assert f.read() == upgraded_config
|
||||||
|
|
||||||
|
# preserved old config
|
||||||
|
backup_config = CONFIG_FILE + f".old.{date.today().isoformat()}"
|
||||||
|
assert os.path.exists(backup_config)
|
||||||
|
with open(backup_config) as f:
|
||||||
|
assert f.read() == duplicate_config
|
||||||
|
|
||||||
|
# migrate jupyterhub_con
|
||||||
@@ -30,9 +30,6 @@ STATE_DIR = os.path.join(INSTALL_PREFIX, 'state')
|
|||||||
CONFIG_DIR = os.path.join(INSTALL_PREFIX, 'config')
|
CONFIG_DIR = os.path.join(INSTALL_PREFIX, 'config')
|
||||||
CONFIG_FILE = os.path.join(CONFIG_DIR, 'config.yaml')
|
CONFIG_FILE = os.path.join(CONFIG_DIR, 'config.yaml')
|
||||||
|
|
||||||
# deprecated config file location
|
|
||||||
OLD_CONFIG_FILE = os.path.join(INSTALL_PREFIX, 'config.yaml')
|
|
||||||
|
|
||||||
|
|
||||||
def set_item_in_config(config, property_path, value):
|
def set_item_in_config(config, property_path, value):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
"""Installation logic for TLJH"""
|
"""Installation logic for TLJH"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from datetime import date
|
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import secrets
|
import secrets
|
||||||
import shutil
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
@@ -16,13 +14,21 @@ from urllib.request import urlopen, URLError
|
|||||||
import pluggy
|
import pluggy
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
from tljh import conda, systemd, traefik, user, apt, hooks
|
from tljh import (
|
||||||
|
apt,
|
||||||
|
conda,
|
||||||
|
hooks,
|
||||||
|
migrator,
|
||||||
|
systemd,
|
||||||
|
traefik,
|
||||||
|
user,
|
||||||
|
)
|
||||||
|
|
||||||
from tljh.config import (
|
from tljh.config import (
|
||||||
CONFIG_DIR,
|
CONFIG_DIR,
|
||||||
CONFIG_FILE,
|
CONFIG_FILE,
|
||||||
HUB_ENV_PREFIX,
|
HUB_ENV_PREFIX,
|
||||||
INSTALL_PREFIX,
|
INSTALL_PREFIX,
|
||||||
OLD_CONFIG_FILE,
|
|
||||||
STATE_DIR,
|
STATE_DIR,
|
||||||
USER_ENV_PREFIX,
|
USER_ENV_PREFIX,
|
||||||
)
|
)
|
||||||
@@ -378,24 +384,7 @@ def ensure_config_yaml(plugin_manager):
|
|||||||
for path in [CONFIG_DIR, os.path.join(CONFIG_DIR, 'jupyterhub_config.d')]:
|
for path in [CONFIG_DIR, os.path.join(CONFIG_DIR, 'jupyterhub_config.d')]:
|
||||||
os.makedirs(path, mode=0o700, exist_ok=True)
|
os.makedirs(path, mode=0o700, exist_ok=True)
|
||||||
|
|
||||||
# handle old TLJH_DIR/config.yaml location
|
migrator.migrate_config_files()
|
||||||
if os.path.exists(OLD_CONFIG_FILE):
|
|
||||||
if os.path.exists(CONFIG_FILE):
|
|
||||||
# new config file already created! still move the config,
|
|
||||||
# but avoid collision
|
|
||||||
timestamp = date.today().isoformat()
|
|
||||||
dest = dest_base = f"{CONFIG_FILE}.old.{timestamp}"
|
|
||||||
i = 0
|
|
||||||
while os.path.exists(dest):
|
|
||||||
# avoid collisions
|
|
||||||
dest = dest_base + f".{i}"
|
|
||||||
i += 1
|
|
||||||
logger.warning(f"Found config in both old ({OLD_CONFIG_FILE}) and new ({CONFIG_FILE}).")
|
|
||||||
logger.warning(f"Moving {OLD_CONFIG_FILE} to {dest} to avoid clobbering. Its contents will be ignored.")
|
|
||||||
else:
|
|
||||||
logger.warning(f"Moving old config file to new location {OLD_CONFIG_FILE} -> {CONFIG_FILE}")
|
|
||||||
dest = CONFIG_FILE
|
|
||||||
shutil.move(OLD_CONFIG_FILE, dest)
|
|
||||||
|
|
||||||
if os.path.exists(CONFIG_FILE):
|
if os.path.exists(CONFIG_FILE):
|
||||||
with open(CONFIG_FILE, 'r') as f:
|
with open(CONFIG_FILE, 'r') as f:
|
||||||
|
|||||||
69
tljh/migrator.py
Normal file
69
tljh/migrator.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
"""Migration utilities for upgrading tljh"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from datetime import date
|
||||||
|
import logging
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from tljh.config import (
|
||||||
|
CONFIG_DIR,
|
||||||
|
CONFIG_FILE,
|
||||||
|
INSTALL_PREFIX,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_file(old_path, new_path):
|
||||||
|
"""Migrate one file from an old location to a new one
|
||||||
|
|
||||||
|
avoids collisions if the new file exists
|
||||||
|
"""
|
||||||
|
if not os.path.exists(old_path):
|
||||||
|
return
|
||||||
|
if os.path.exists(new_path):
|
||||||
|
# new config file already created! still move the config,
|
||||||
|
# but avoid collision
|
||||||
|
timestamp = date.today().isoformat()
|
||||||
|
dest = dest_base = f"{new_path}.old.{timestamp}"
|
||||||
|
i = 0
|
||||||
|
while os.path.exists(dest):
|
||||||
|
# avoid collisions
|
||||||
|
dest = dest_base + f".{i}"
|
||||||
|
i += 1
|
||||||
|
logger.warning(f"Found file in both old ({old_path}) and new ({new_path}).")
|
||||||
|
logger.warning(
|
||||||
|
f"Moving {old_path} to {dest} to avoid clobbering. Its contents will be ignored."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
dest = new_path
|
||||||
|
shutil.move(old_path, dest)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_directory(old_dir, new_dir):
|
||||||
|
"""Migrate a directory to a new location"""
|
||||||
|
if not os.path.exists(old_dir):
|
||||||
|
return
|
||||||
|
if os.path.exists(new_dir):
|
||||||
|
# both dirs exist
|
||||||
|
for f in os.listdir(old_dir):
|
||||||
|
src = os.path.join(old_dir, f)
|
||||||
|
dest = os.path.join(new_dir, f)
|
||||||
|
if os.path.isdir(src):
|
||||||
|
migrate_directory(src, dest)
|
||||||
|
else:
|
||||||
|
migrate_file(src, dest)
|
||||||
|
else:
|
||||||
|
logger.warning(f"Moving directory to new location {old_dir} -> {new_dir}")
|
||||||
|
shutil.move(old_dir, new_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_config_files():
|
||||||
|
"""Migrate config files to their new locations"""
|
||||||
|
# handle old TLJH_DIR/config.yaml location
|
||||||
|
migrate_file(os.path.join(INSTALL_PREFIX, "config.yaml"), CONFIG_FILE)
|
||||||
|
migrate_directory(
|
||||||
|
os.path.join(INSTALL_PREFIX, "jupyterhub_config.d"),
|
||||||
|
os.path.join(CONFIG_DIR, "jupyterhub_config.d"),
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user