Implement actual update function, lazy-load online_packages

This commit is contained in:
Disassembler 2019-10-17 08:11:10 +02:00
parent ecb09001d4
commit be36199640
No known key found for this signature in database
GPG Key ID: 524BD33A0EE29499
3 changed files with 40 additions and 37 deletions

View File

@ -56,7 +56,6 @@ def print_apps(packages):
def list_online(): def list_online():
pm = PkgMgr() pm = PkgMgr()
pm.fetch_online_packages()
apps = pm.online_packages['apps'] apps = pm.online_packages['apps']
if apps: if apps:
print_apps(apps) print_apps(apps)

View File

@ -15,6 +15,10 @@ from . import lxcmgr
from . import svcmgr from . import svcmgr
from .paths import LXC_STORAGE_DIR, REPO_CACHE_DIR, REPO_CONF_FILE, REPO_LOCAL_FILE, REPO_LOCK, REPO_SIG_FILE from .paths import LXC_STORAGE_DIR, REPO_CACHE_DIR, REPO_CONF_FILE, REPO_LOCAL_FILE, REPO_LOCK, REPO_SIG_FILE
INSTALL_SCRIPT = 'install.sh'
UPDATE_SCRIPT = 'update.sh'
UNINSTALL_SCRIPT = 'uninstall.sh'
class Stage(Enum): class Stage(Enum):
QUEUED = 1 QUEUED = 1
DOWNLOAD = 2 DOWNLOAD = 2
@ -49,10 +53,20 @@ class PkgMgr:
def __init__(self): def __init__(self):
self.repo_url = None self.repo_url = None
self.repo_auth = None self.repo_auth = None
self.online_packages = None self._online_packages = None
with open(REPO_LOCAL_FILE, 'r') as f: with open(REPO_LOCAL_FILE, 'r') as f:
self.installed_packages = json.load(f) self.installed_packages = json.load(f)
@property
def online_packages(self):
if not self._online_packages:
# Fetches and verifies online packages. Can raise InvalidSignature
packages = self.get_repo_resource('packages').content
packages_sig = self.get_repo_resource('packages.sig').content
crypto.verify_signature(REPO_SIG_FILE, packages, packages_sig)
self._online_packages = json.loads(packages)
return self._online_packages
def save_installed_packages(self): def save_installed_packages(self):
with open(REPO_LOCAL_FILE, 'w') as f: with open(REPO_LOCAL_FILE, 'w') as f:
json.dump(self.installed_packages, f, sort_keys=True, indent=4) json.dump(self.installed_packages, f, sort_keys=True, indent=4)
@ -79,21 +93,26 @@ class PkgMgr:
raise RepoBadRequest(r.url) raise RepoBadRequest(r.url)
return r return r
def fetch_online_packages(self):
# Fetches and verifies online packages. Can raise InvalidSignature
packages = self.get_repo_resource('packages').content
packages_sig = self.get_repo_resource('packages.sig').content
crypto.verify_signature(REPO_SIG_FILE, packages, packages_sig)
self.online_packages = json.loads(packages)
@flock.flock_ex(REPO_LOCK) @flock.flock_ex(REPO_LOCK)
def install_app(self, app): def install_app(self, app):
# Main installation function. Wrapper for download, registration and install script # Main installation function. Wrapper for download, registration and install script
if app.name in self.installed_packages['apps']: if app.name in self.installed_packages['apps']:
app.stage = Stage.DONE app.stage = Stage.DONE
return return
if not self.online_packages: self.download_and_unpack_deps(app)
self.fetch_online_packages() # Run setup scripts
app.stage = Stage.INSTALL
# Run uninstall script to clean previous failed installation
self.run_script(app.name, UNINSTALL_SCRIPT)
# Build containers and services
self.create_containers(self.online_packages['apps'][app.name]['containers'])
# Run install script and register the app
self.run_script(app.name, INSTALL_SCRIPT)
self.register_app(app.name, self.online_packages['apps'][app.name])
app.stage = Stage.DONE
def download_and_unpack_deps(self, app):
# Common download and unpack function for install and update
# Get all packages on which the app and its containers depend and which have not been installed yet # Get all packages on which the app and its containers depend and which have not been installed yet
images = [] images = []
image_deps = [container['image'] for container in self.online_packages['apps'][app.name]['containers'].values()] image_deps = [container['image'] for container in self.online_packages['apps'][app.name]['containers'].values()]
@ -116,16 +135,6 @@ class PkgMgr:
self.register_image(image, self.online_packages['images'][image]) self.register_image(image, self.online_packages['images'][image])
self.purge_scripts(app.name) self.purge_scripts(app.name)
self.unpack_scripts(app.name) self.unpack_scripts(app.name)
# Run setup scripts
app.stage = Stage.INSTALL
# Run uninstall script to clean previous failed installation
self.run_uninstall_script(app.name)
# Build containers and services
self.create_containers(self.online_packages['apps'][app.name]['containers'])
# Run install script and register the app
self.run_install_script(app.name)
self.register_app(app.name, self.online_packages['apps'][app.name])
app.stage = Stage.DONE
def download_image(self, app, image): def download_image(self, app, image):
# Download image archive and verify hash # Download image archive and verify hash
@ -184,14 +193,6 @@ class PkgMgr:
subprocess.run(['tar', 'xJf', tmp_archive], cwd=os.path.join(REPO_CACHE_DIR, 'apps'), check=True) subprocess.run(['tar', 'xJf', tmp_archive], cwd=os.path.join(REPO_CACHE_DIR, 'apps'), check=True)
os.unlink(tmp_archive) os.unlink(tmp_archive)
def run_uninstall_script(self, app):
# Runs uninstall.sh for an app, if the script is present
self.run_script(app, 'uninstall.sh')
def run_install_script(self, app):
# Runs install.sh for a package, if the script is present
self.run_script(app, 'install.sh')
def run_script(self, app, script): def run_script(self, app, script):
# Runs script for an app, if the script is present # Runs script for an app, if the script is present
script_dir = os.path.join(REPO_CACHE_DIR, 'apps', app) script_dir = os.path.join(REPO_CACHE_DIR, 'apps', app)
@ -239,7 +240,7 @@ class PkgMgr:
app.stage = Stage.DONE app.stage = Stage.DONE
return return
app.stage = Stage.UNINSTALL app.stage = Stage.UNINSTALL
self.run_uninstall_script(app.name) self.run_script(app.name, UNINSTALL_SCRIPT)
self.destroy_containers(self.installed_packages['apps'][app.name]['containers']) self.destroy_containers(self.installed_packages['apps'][app.name]['containers'])
self.purge_scripts(app.name) self.purge_scripts(app.name)
self.unregister_app(app.name) self.unregister_app(app.name)
@ -259,17 +260,20 @@ class PkgMgr:
self.purge_layer(layer) self.purge_layer(layer)
@flock.flock_ex(REPO_LOCK) @flock.flock_ex(REPO_LOCK)
def update_app(self, app, item): def update_app(self, app):
# Main update function. # Main update function.
# TODO: Implement actual update self.download_and_unpack_deps(app)
uninstall_app(app) # Run setup scripts
install_app(app, item) app.stage = Stage.UPDATE
# Build containers and services
self.create_containers(self.online_packages['apps'][app.name]['containers'])
# Run update script and register the app
self.run_script(app.name, UPDATE_SCRIPT)
self.register_app(app.name, self.online_packages['apps'][app.name])
app.stage = Stage.DONE app.stage = Stage.DONE
def has_update(self, app): def has_update(self, app):
# Check if online repository list a newer version of app # Check if online repository list a newer version of app
if not self.online_packages:
self.fetch_online_packages()
if app not in self.online_packages['apps']: if app not in self.online_packages['apps']:
# Application has been removed from online repo # Application has been removed from online repo
return False return False

View File

@ -174,7 +174,7 @@ class WSGIApp:
# Application manager view. # Application manager view.
repo_error = None repo_error = None
try: try:
self.appmgr.pkgmgr.fetch_online_packages() self.appmgr.pkgmgr.fetch_online_packages() # TODO: fetch is now automatic in @property
except InvalidSignature: except InvalidSignature:
repo_error = request.session.lang.invalid_packages_signature() repo_error = request.session.lang.invalid_packages_signature()
except Unauthorized: except Unauthorized: