Destroy containers on install to cleanup previous
This commit is contained in:
parent
7591cf2d47
commit
6045349f9c
@ -118,10 +118,12 @@ def install_app(app):
|
|||||||
|
|
||||||
def update_app(app):
|
def update_app(app):
|
||||||
pm = PkgMgr()
|
pm = PkgMgr()
|
||||||
|
app = App(app)
|
||||||
run_install_action(pm.update_app, app)
|
run_install_action(pm.update_app, app)
|
||||||
|
|
||||||
def uninstall_app(app):
|
def uninstall_app(app):
|
||||||
pm = PkgMgr()
|
pm = PkgMgr()
|
||||||
|
app = App(app)
|
||||||
run_install_action(pm.uninstall_app, app)
|
run_install_action(pm.uninstall_app, app)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
@ -109,6 +109,7 @@ class PkgMgr:
|
|||||||
self.download_scripts(app)
|
self.download_scripts(app)
|
||||||
# Purge old data to clean previous failed installation and unpack downloaded archives
|
# Purge old data to clean previous failed installation and unpack downloaded archives
|
||||||
app.stage = Stage.UNPACK
|
app.stage = Stage.UNPACK
|
||||||
|
self.destroy_containers(self.online_packages['apps'][app.name]['containers'])
|
||||||
for image in images:
|
for image in images:
|
||||||
self.purge_image(image)
|
self.purge_image(image)
|
||||||
self.unpack_image(image)
|
self.unpack_image(image)
|
||||||
@ -120,8 +121,7 @@ class PkgMgr:
|
|||||||
# Run uninstall script to clean previous failed installation
|
# Run uninstall script to clean previous failed installation
|
||||||
self.run_uninstall_script(app.name)
|
self.run_uninstall_script(app.name)
|
||||||
# Build containers and services
|
# Build containers and services
|
||||||
self.create_containers(app.name)
|
self.create_containers(self.online_packages['apps'][app.name]['containers'])
|
||||||
# TODO: Create services
|
|
||||||
# Run install script and register the app
|
# Run install script and register the app
|
||||||
self.run_install_script(app.name)
|
self.run_install_script(app.name)
|
||||||
self.register_app(app.name, self.online_packages['apps'][app.name])
|
self.register_app(app.name, self.online_packages['apps'][app.name])
|
||||||
@ -209,38 +209,38 @@ class PkgMgr:
|
|||||||
del self.installed_packages['apps'][app]
|
del self.installed_packages['apps'][app]
|
||||||
self.save_installed_packages()
|
self.save_installed_packages()
|
||||||
|
|
||||||
def create_containers(self, app):
|
def create_containers(self, containers):
|
||||||
# Create LXC containers from image and app metadata
|
# Create LXC containers from image and app metadata
|
||||||
for container in self.online_packages['apps'][app]['containers']:
|
for container in containers:
|
||||||
image = self.online_packages['apps'][app]['containers'][container]['image']
|
image = containers[container]['image']
|
||||||
image = self.online_packages['images'][image].copy()
|
image = self.online_packages['images'][image].copy()
|
||||||
if 'mounts' in self.online_packages['apps'][app]['containers'][container]:
|
if 'mounts' in containers[container]:
|
||||||
image['mounts'] = self.online_packages['apps'][app]['containers'][container]['mounts']
|
image['mounts'] = containers[container]['mounts']
|
||||||
if 'depends' in self.online_packages['apps'][app]['containers'][container]:
|
if 'depends' in containers[container]:
|
||||||
image['depends'] = self.online_packages['apps'][app]['containers'][container]['depends']
|
image['depends'] = containers[container]['depends']
|
||||||
lxcmgr.create_container(container, image)
|
lxcmgr.create_container(container, image)
|
||||||
svcmgr.create_service(app, container, image)
|
svcmgr.create_service(container, image)
|
||||||
|
|
||||||
|
def destroy_containers(self, containers):
|
||||||
|
# Destroy LXC containers
|
||||||
|
for container in containers:
|
||||||
|
svcmgr.delete_service(container)
|
||||||
|
lxcmgr.destroy_container(container)
|
||||||
|
|
||||||
@flock.flock_ex(REPO_LOCK)
|
@flock.flock_ex(REPO_LOCK)
|
||||||
def uninstall_app(self, app):
|
def uninstall_app(self, app):
|
||||||
# Main uninstallation function. Wrapper for uninstall script and filesystem purge
|
# Main uninstallation function. Wrapper for uninstall script and filesystem purge
|
||||||
if app not in self.installed_packages['apps']:
|
if app.name not in self.installed_packages['apps']:
|
||||||
app.stage = Stage.DONE
|
app.stage = Stage.DONE
|
||||||
return
|
return
|
||||||
app.stage = Stage.UNINSTALL
|
app.stage = Stage.UNINSTALL
|
||||||
self.run_uninstall_script(app)
|
self.run_uninstall_script(app.name)
|
||||||
self.destroy_containers(app)
|
self.destroy_containers(self.installed_packages['apps'][app.name]['containers'])
|
||||||
self.purge_scripts(app)
|
self.purge_scripts(app.name)
|
||||||
self.unregister_app(app)
|
self.unregister_app(app.name)
|
||||||
self.purge_unused_layers()
|
self.purge_unused_layers()
|
||||||
app.stage = Stage.DONE
|
app.stage = Stage.DONE
|
||||||
|
|
||||||
def destroy_containers(self, app):
|
|
||||||
# Destroy LXC containers
|
|
||||||
for container in self.installed_packages['apps'][app]['containers']:
|
|
||||||
svcmgr.delete_service(container)
|
|
||||||
lxcmgr.destroy_container(container)
|
|
||||||
|
|
||||||
def purge_unused_layers(self):
|
def purge_unused_layers(self):
|
||||||
# Remove layers which are no longer used by any installed application
|
# Remove layers which are no longer used by any installed application
|
||||||
layers = set(os.list(LXC_STORAGE_DIR))
|
layers = set(os.list(LXC_STORAGE_DIR))
|
||||||
|
@ -6,14 +6,14 @@ import subprocess
|
|||||||
from .paths import AUTOSTART_SVC_DIR, SERVICE_DIR, STARTED_SVC_DIR
|
from .paths import AUTOSTART_SVC_DIR, SERVICE_DIR, STARTED_SVC_DIR
|
||||||
from .templates import SERVICE
|
from .templates import SERVICE
|
||||||
|
|
||||||
def create_service(app, container, image):
|
def create_service(container, image):
|
||||||
depends = ' '.join(image['depends']) if 'depends' in image else ''
|
depends = ' '.join(image['depends']) if 'depends' in image else ''
|
||||||
# Add ready check to start_post
|
# Add ready check to start_post
|
||||||
# This could arguably be better done via some template engine, but introducing one for 2 template files seems like overkill
|
# This could arguably be better done via some template engine, but introducing one for 2 template files seems like overkill
|
||||||
start_post = '\nstart_post() {{\n timeout -t 60 lxc-attach {} -- sh -c \'until {}; do sleep 0.1; done\'\n}}\n'.format(container, image['ready']) if 'ready' in image else ''
|
start_post = '\nstart_post() {{\n timeout -t 60 lxc-attach {} -- sh -c \'until {}; do sleep 0.1; done\'\n}}\n'.format(container, image['ready']) if 'ready' in image else ''
|
||||||
service_file = os.path.join(SERVICE_DIR, container)
|
service_file = os.path.join(SERVICE_DIR, container)
|
||||||
with open(service_file, 'w') as f:
|
with open(service_file, 'w') as f:
|
||||||
f.write(SERVICE.format(app=app, container=container, depends=depends, start_post=start_post))
|
f.write(SERVICE.format(container=container, depends=depends, start_post=start_post))
|
||||||
os.chmod(service_file, 0o755)
|
os.chmod(service_file, 0o755)
|
||||||
update_services()
|
update_services()
|
||||||
|
|
||||||
@ -24,9 +24,9 @@ def delete_service(service):
|
|||||||
update_service_autostart(service, False)
|
update_service_autostart(service, False)
|
||||||
try:
|
try:
|
||||||
os.unlink(os.path.join(SERVICE_DIR, service))
|
os.unlink(os.path.join(SERVICE_DIR, service))
|
||||||
|
update_services()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
update_services()
|
|
||||||
|
|
||||||
def update_services():
|
def update_services():
|
||||||
subprocess.run(['/sbin/rc-update', '-u'], check=True)
|
subprocess.run(['/sbin/rc-update', '-u'], check=True)
|
||||||
@ -39,14 +39,14 @@ def stop_service(service):
|
|||||||
if is_service_started(service):
|
if is_service_started(service):
|
||||||
subprocess.run(['/sbin/service', service, 'stop'], check=True)
|
subprocess.run(['/sbin/service', service, 'stop'], check=True)
|
||||||
|
|
||||||
def is_service_started(self, app):
|
def is_service_started(service):
|
||||||
# Check OpenRC service status without calling any binary
|
# Check OpenRC service status without calling any binary
|
||||||
return os.path.exists(os.path.join(STARTED_SVC_DIR, app))
|
return os.path.exists(os.path.join(STARTED_SVC_DIR, service))
|
||||||
|
|
||||||
def is_service_autostarted(self, app):
|
def is_service_autostarted(service):
|
||||||
# Check OpenRC service enablement
|
# Check OpenRC service enablement
|
||||||
return os.path.exists(os.path.join(AUTOSTART_SVC_DIR, app))
|
return os.path.exists(os.path.join(AUTOSTART_SVC_DIR, service))
|
||||||
|
|
||||||
def update_service_autostart(self, service, enabled):
|
def update_service_autostart(service, enabled):
|
||||||
# Add/remove the app to OpenRC default runlevel
|
# Add/remove the service to/from OpenRC default runlevel
|
||||||
subprocess.run(['/sbin/rc-update', 'add' if enabled else 'del', service])
|
subprocess.run(['/sbin/rc-update', 'add' if enabled else 'del', service])
|
||||||
|
@ -51,7 +51,7 @@ lxc.include = /usr/share/lxc/config/userns.conf
|
|||||||
|
|
||||||
SERVICE = """#!/sbin/openrc-run
|
SERVICE = """#!/sbin/openrc-run
|
||||||
|
|
||||||
description="{app} {container} LXC container"
|
description="{container} LXC container"
|
||||||
|
|
||||||
depend() {{
|
depend() {{
|
||||||
need cgroups {depends}
|
need cgroups {depends}
|
||||||
|
Loading…
Reference in New Issue
Block a user