mirror of
https://github.com/jupyterhub/the-littlest-jupyterhub.git
synced 2025-12-18 21:54:05 +08:00
Merge pull request #994 from minrk/consolidate_lock
consolidate lock file handling
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
filelock
|
||||
packaging
|
||||
pytest
|
||||
pytest-cov
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
filelock
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-asyncio
|
||||
|
||||
1
setup.py
1
setup.py
@@ -15,6 +15,7 @@ setup(
|
||||
"jinja2",
|
||||
"pluggy==1.*",
|
||||
"backoff",
|
||||
"filelock",
|
||||
"requests",
|
||||
"bcrypt",
|
||||
"jupyterhub-traefik-proxy==1.*",
|
||||
|
||||
107
tljh/config.py
107
tljh/config.py
@@ -18,9 +18,11 @@ import re
|
||||
import sys
|
||||
import time
|
||||
from collections.abc import Mapping, Sequence
|
||||
from contextlib import contextmanager
|
||||
from copy import deepcopy
|
||||
|
||||
import requests
|
||||
from filelock import FileLock, Timeout
|
||||
|
||||
from .yaml import yaml
|
||||
|
||||
@@ -32,6 +34,22 @@ CONFIG_DIR = os.path.join(INSTALL_PREFIX, "config")
|
||||
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.yaml")
|
||||
|
||||
|
||||
@contextmanager
|
||||
def config_file_lock(config_path, timeout=1):
|
||||
"""Context manager to acquire the config file lock"""
|
||||
lock_file = f"{config_path}.lock"
|
||||
try:
|
||||
with FileLock(lock_file).acquire(timeout=timeout):
|
||||
yield
|
||||
|
||||
except Timeout:
|
||||
print(
|
||||
f"Another instance of tljh-config holds the lock {lock_file}.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def set_item_in_config(config, property_path, value):
|
||||
"""
|
||||
Set key at property_path to value in config & return new config.
|
||||
@@ -169,9 +187,10 @@ def validate_config(config, validate):
|
||||
print(
|
||||
f"Config validation error: {e.message}.\n"
|
||||
"You can still apply this change without validation by re-running your command with the --no-validate flag.\n"
|
||||
"If you think this validation error is incorrect, please report it to https://github.com/jupyterhub/the-littlest-jupyterhub/issues."
|
||||
"If you think this validation error is incorrect, please report it to https://github.com/jupyterhub/the-littlest-jupyterhub/issues.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
exit()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def show_config(config_path):
|
||||
@@ -186,88 +205,52 @@ def set_config_value(config_path, key_path, value, validate=True):
|
||||
"""
|
||||
Set key at key_path in config_path to value
|
||||
"""
|
||||
from filelock import FileLock, Timeout
|
||||
with config_file_lock(config_path):
|
||||
config = get_current_config(config_path)
|
||||
config = set_item_in_config(config, key_path, value)
|
||||
validate_config(config, validate)
|
||||
|
||||
lock_file = f"{config_path}.lock"
|
||||
lock = FileLock(lock_file)
|
||||
try:
|
||||
with lock.acquire(timeout=1):
|
||||
config = get_current_config(config_path)
|
||||
config = set_item_in_config(config, key_path, value)
|
||||
validate_config(config, validate)
|
||||
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
except Timeout:
|
||||
print(f"Another instance of tljh-config holds the lock {lock_file}")
|
||||
exit(1)
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
|
||||
def unset_config_value(config_path, key_path, validate=True):
|
||||
"""
|
||||
Unset key at key_path in config_path
|
||||
"""
|
||||
from filelock import FileLock, Timeout
|
||||
with config_file_lock(config_path):
|
||||
config = get_current_config(config_path)
|
||||
config = unset_item_from_config(config, key_path)
|
||||
validate_config(config, validate)
|
||||
|
||||
lock_file = f"{config_path}.lock"
|
||||
lock = FileLock(lock_file)
|
||||
try:
|
||||
with lock.acquire(timeout=1):
|
||||
config = get_current_config(config_path)
|
||||
config = unset_item_from_config(config, key_path)
|
||||
validate_config(config, validate)
|
||||
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
except Timeout:
|
||||
print(f"Another instance of tljh-config holds the lock {lock_file}")
|
||||
exit(1)
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
|
||||
def add_config_value(config_path, key_path, value, validate=True):
|
||||
"""
|
||||
Add value to list at key_path
|
||||
"""
|
||||
from filelock import FileLock, Timeout
|
||||
with config_file_lock(config_path):
|
||||
config = get_current_config(config_path)
|
||||
config = add_item_to_config(config, key_path, value)
|
||||
validate_config(config, validate)
|
||||
|
||||
lock_file = f"{config_path}.lock"
|
||||
lock = FileLock(lock_file)
|
||||
try:
|
||||
with lock.acquire(timeout=1):
|
||||
config = get_current_config(config_path)
|
||||
config = add_item_to_config(config, key_path, value)
|
||||
validate_config(config, validate)
|
||||
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
except Timeout:
|
||||
print(f"Another instance of tljh-config holds the lock {lock_file}")
|
||||
exit(1)
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
|
||||
def remove_config_value(config_path, key_path, value, validate=True):
|
||||
"""
|
||||
Remove value from list at key_path
|
||||
"""
|
||||
from filelock import FileLock, Timeout
|
||||
with config_file_lock(config_path):
|
||||
config = get_current_config(config_path)
|
||||
config = remove_item_from_config(config, key_path, value)
|
||||
validate_config(config, validate)
|
||||
|
||||
lock_file = f"{config_path}.lock"
|
||||
lock = FileLock(lock_file)
|
||||
try:
|
||||
with lock.acquire(timeout=1):
|
||||
config = get_current_config(config_path)
|
||||
config = remove_item_from_config(config, key_path, value)
|
||||
validate_config(config, validate)
|
||||
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
except Timeout:
|
||||
print(f"Another instance of tljh-config holds the lock {lock_file}")
|
||||
exit(1)
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
|
||||
def get_current_config(config_path):
|
||||
|
||||
@@ -26,6 +26,3 @@ jupyterhub-idle-culler>=1.2.1,<2
|
||||
# ref: https://github.com/jupyterhub/the-littlest-jupyterhub/issues/289
|
||||
#
|
||||
pycurl>=7.45.2,<8
|
||||
|
||||
# filelock is used to help us do atomic operations on config file(s)
|
||||
filelock>=3.15.4,<4
|
||||
|
||||
Reference in New Issue
Block a user