From 780e469f823b9dd2451908be49a974380d55d8d3 Mon Sep 17 00:00:00 2001 From: Disassembler Date: Fri, 26 Oct 2018 21:52:06 +0200 Subject: [PATCH] Add uninstallation --- basic/srv/vm/mgr/pkgmgr.py | 38 ++++++++++++++++++++++----------- basic/srv/vm/mgr/wsgiapp.py | 19 ++++++++--------- basic/srv/vm/static/js/admin.js | 2 +- zz-build/usr/bin/lxc-pack | 4 ++-- 4 files changed, 37 insertions(+), 26 deletions(-) diff --git a/basic/srv/vm/mgr/pkgmgr.py b/basic/srv/vm/mgr/pkgmgr.py index 051f720..8c79c09 100644 --- a/basic/srv/vm/mgr/pkgmgr.py +++ b/basic/srv/vm/mgr/pkgmgr.py @@ -40,12 +40,13 @@ class PackageManager: # Registers pending installation. Fetch online packages here instead of install_pacakges() to fail early if the repo isn't reachable self.fetch_online_packages() self.pending = 1 - deps = [d for d in self.get_deps(name) if d not in self.conf['packages']] + # Return total size for download + deps = [d for d in self.get_install_deps(name) if d not in self.conf['packages']] return sum(self.online_packages[d]['size'] for d in deps) def install_package(self, name): # Main installation function. Wrapper for download, registration and install script - deps = [d for d in self.get_deps(name) if d not in self.conf['packages']] + deps = [d for d in self.get_install_deps(name) if d not in self.conf['packages']] for dep in deps: self.download_package(dep) self.register_package(dep) @@ -54,10 +55,12 @@ class PackageManager: def uninstall_package(self, name): # Main uninstallation function. Wrapper for uninstall script, filesystem purge and unregistration - # TODO: Get dependencies which can be uninstalled - self.run_uninstall_script(name) - self.purge_package(name) - self.unregister_package(name) + deps = self.get_install_deps(name, False)[::-1] + for dep in deps: + if dep not in self.get_uninstall_deps(): + self.run_uninstall_script(dep) + self.purge_package(dep) + self.unregister_package(dep) def download_package(self, name): # Downloads, verifies, unpacks and sets up a package @@ -78,7 +81,7 @@ class PackageManager: # Removes package and shared data from filesystem shutil.rmtree(os.path.join(LXC_ROOT, self.conf['packages'][name]['lxcpath'])) srv_dir = os.path.join('/srv/', name) - if os.path.exsit(srv_dir): + if os.path.exists(srv_dir): shutil.rmtree(srv_dir) def run_install_script(self, name): @@ -123,12 +126,21 @@ class PackageManager: del self.conf['apps'][name] self.conf.save() - def get_deps(self, name): - # Flatten dependency tree for a package - deps = self.online_packages[name]['deps'].copy() - for dep in deps: - deps[:0] = [d for d in self.get_deps(dep) if d not in deps] - deps.append(name) + def get_install_deps(self, name, online=True): + # Flatten dependency tree for a package while preserving the dependency order + packages = self.online_packages if online else self.conf['packages'] + deps = packages[name]['deps'].copy() + for dep in deps[::-1]: + deps[:0] = [d for d in self.get_install_deps(dep, online)] + deps = list(dict.fromkeys(deps + [name])) + return deps + + def get_uninstall_deps(self): + # Create reverse dependency tree for all installed packages + deps = {} + for pkg in self.conf['packages']: + for d in self.conf['packages'][pkg]['deps']: + deps.setdefault(d, []).append(pkg) return deps def hash_file(file_path): diff --git a/basic/srv/vm/mgr/wsgiapp.py b/basic/srv/vm/mgr/wsgiapp.py index 29c4793..1742608 100644 --- a/basic/srv/vm/mgr/wsgiapp.py +++ b/basic/srv/vm/mgr/wsgiapp.py @@ -274,7 +274,8 @@ class WSGIApp(object): # Stops application along with its dependencies try: app = request.form['app'] - self.vmmgr.stop_app(app) + if tools.is_service_started(app): + self.vmmgr.stop_app(app) except (BadRequest, InvalidValueException): return self.render_json({'error': request.session.lang.malformed_request()}) except: @@ -294,14 +295,14 @@ class WSGIApp(object): except: return self.render_json({'error': request.session.lang.package_manager_error()}) app_title = self.pkgmgr.online_packages[app]['title'] - response = self.render_json({'ok': self.render_setup_apps_row(app, app_title, round(total_size / 1048576, 1))}) + response = self.render_json({'ok': self.render_setup_apps_row(app, app_title, '{:.1f}'.print(total_size / 1048576))}) response.call_on_close(lambda: self.pkgmgr.install_package(app)) return response def get_install_progress_action(self, request): + # Gets pending installation status if self.pkgmgr.pending: - return self.render_json({'progress': round(self.pkgmgr.pending / 1048576, 1)}) - self.conf.load() + return self.render_json({'progress': '{:.1f}'.print(self.pkgmgr.pending / 1048576)}) app = request.form['app'] app_title = self.conf['apps'][app]['title'] return self.render_json({'ok': self.render_setup_apps_row(app, app_title)}) @@ -310,16 +311,14 @@ class WSGIApp(object): # Uninstalls application try: app = request.form['app'] + app_title = self.conf['apps'][app]['title'] self.vmmgr.stop_app(app) - pkgmgr = PackageManager() - pkgmgr.uninstall_package(app) + self.pkgmgr.uninstall_package(app) except (BadRequest, InvalidValueException): return self.render_json({'error': request.session.lang.malformed_request()}) except: - return self.render_json({'error': request.session.lang.package_manager_error()}) - # Get title from old data, then reload config - app_title = self.conf['apps'][app]['title'] - self.conf.load() + raise + # return self.render_json({'error': request.session.lang.package_manager_error()}) return self.render_json({'ok': self.render_setup_apps_row(app, app_title)}) def update_password_action(self, request): diff --git a/basic/srv/vm/static/js/admin.js b/basic/srv/vm/static/js/admin.js index 47fe08e..db5ffb8 100644 --- a/basic/srv/vm/static/js/admin.js +++ b/basic/srv/vm/static/js/admin.js @@ -16,7 +16,7 @@ $(function() { $('#update-password').on('submit', update_password); $('#reboot-vm').on('click', reboot_vm); $('#shutdown-vm').on('click', shutdown_vm); - window.setInterval(check_progress, 1000); + window.setInterval(check_progress, 2000); }); function update_host() { diff --git a/zz-build/usr/bin/lxc-pack b/zz-build/usr/bin/lxc-pack index 10d8548..33f9000 100755 --- a/zz-build/usr/bin/lxc-pack +++ b/zz-build/usr/bin/lxc-pack @@ -46,9 +46,9 @@ def pack(pkg_file): cwd = os.path.dirname(os.path.abspath(pkg_file)) subprocess.run(['tar', '--transform', 's|^|srv/{}/|'.format(pkg_name), '-rpf', tar_path, 'install', 'install.sh', 'upgrade', 'upgrade.sh', 'uninstall', 'uninstall.sh'], cwd=cwd) # Compress the tarball with xz (LZMA2) - print('Compressing', tar_path, '({} MB)'.format(round(os.path.getsize(tar_path)/1048576, 2))) + print('Compressing', tar_path, '({0:.2f} MB)'.format(os.path.getsize(tar_path)/1048576)) subprocess.run(['xz', '-9', tar_path]) - print('Compressed ', xz_path, '({} MB)'.format(round(os.path.getsize(xz_path)/1048576, 2))) + print('Compressed ', xz_path, '({0:.2f} MB)'.format(os.path.getsize(xz_path)/1048576)) # Register package print('Registering package')