Implement service manager
This commit is contained in:
parent
7b045cf9c3
commit
d14fba7ec1
@ -97,6 +97,7 @@ def install_app(app):
|
||||
print_install_status(app)
|
||||
|
||||
def print_install_status(app):
|
||||
# Prints current status of the installation. Uses ANSI "erase line" and "carriage return" to rewrite the status on single line.
|
||||
if app.stage == Stage.QUEUED:
|
||||
print('\x1b[KQueued...', end='\r')
|
||||
elif app.stage == Stage.DOWNLOAD:
|
||||
|
@ -7,8 +7,6 @@ from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
|
||||
from .paths import REPO_SIG_FILE
|
||||
|
||||
def verify_signature(public_key_path, input_data, signature_data):
|
||||
# Verifies ECDSA HMAC SHA512 signature of a file
|
||||
with open(public_key_path, 'rb') as f:
|
||||
|
@ -12,7 +12,8 @@ from .templates import LXC_CONTAINER
|
||||
def prepare_container(container, layers):
|
||||
# Remove ephemeral layer data
|
||||
clean_ephemeral_layer(container)
|
||||
# Prepare and mount overlayfs
|
||||
# Prepare and mount overlayfs. This needs to be done before handing over control to LXC as we use unprivileged containers
|
||||
# which don't have the capability to mount overlays - https://www.spinics.net/lists/linux-fsdevel/msg105877.html
|
||||
rootfs = os.path.join(LXC_ROOT, container, 'rootfs')
|
||||
# Unmount rootfs in case it remained mounted for whatever reason
|
||||
subprocess.run(['umount', rootfs])
|
||||
|
@ -13,3 +13,8 @@ HOSTS_LOCK = '/var/lock/lxcmgr-hosts.lock'
|
||||
LXC_LOGS = '/var/log/lxc'
|
||||
LXC_ROOT = '/var/lib/lxc'
|
||||
LXC_STORAGE_DIR = '/var/lib/lxcmgr/storage'
|
||||
|
||||
# Services
|
||||
AUTOSTART_SVC_DIR = '/etc/runlevels/default'
|
||||
SERVICE_DIR = '/etc/init.d'
|
||||
STARTED_SVC_DIR = '/run/openrc/started'
|
||||
|
@ -12,6 +12,7 @@ from pkg_resources import parse_version
|
||||
from . import crypto
|
||||
from . import flock
|
||||
from . import lxcmgr
|
||||
from . import svcmgr
|
||||
from .paths import LXC_STORAGE_DIR, REPO_CACHE_DIR, REPO_CONF_FILE, REPO_LOCAL_FILE, REPO_LOCK, REPO_SIG_FILE
|
||||
|
||||
class Stage(Enum):
|
||||
@ -99,7 +100,7 @@ class PkgMgr:
|
||||
images.extend(self.online_packages['images'][image]['layers'])
|
||||
images = [image for image in set(images) if image not in self.installed_packages['images']]
|
||||
# Calculate bytes to download
|
||||
app.bytes_total = sum(self.online_packages['images'][image]['size'] for image in images) + self.online_packages['apps'][app.name]['size']
|
||||
app.bytes_total = sum(self.online_packages['images'][image]['pkgsize'] for image in images) + self.online_packages['apps'][app.name]['pkgsize']
|
||||
# Download layers and setup script files
|
||||
app.stage = Stage.DOWNLOAD
|
||||
for image in images:
|
||||
@ -214,8 +215,10 @@ class PkgMgr:
|
||||
image = self.online_packages['images'][image].copy()
|
||||
if 'mounts' in self.online_packages['apps'][app]['containers'][container]:
|
||||
image['mounts'] = self.online_packages['apps'][app]['containers'][container]['mounts']
|
||||
if 'depends' in self.online_packages['apps'][app]['containers'][container]
|
||||
image['depends'] = self.online_packages['apps'][app]['containers'][container]['depends']
|
||||
lxcmgr.create_container(container, image)
|
||||
# TODO: Create services
|
||||
svcmgr.create_service(app, container, image)
|
||||
|
||||
@flock.flock_ex(REPO_LOCK)
|
||||
def uninstall_app(self, app):
|
||||
@ -225,11 +228,13 @@ class PkgMgr:
|
||||
self.run_uninstall_script(app)
|
||||
self.destroy_containers(app)
|
||||
self.purge_scripts(app)
|
||||
self.unregister_app(app)
|
||||
self.purge_unused_layers()
|
||||
|
||||
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):
|
||||
|
48
usr/lib/python3.6/lxcmgr/svcmgr.py
Normal file
48
usr/lib/python3.6/lxcmgr/svcmgr.py
Normal file
@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from .paths import AUTOSTART_SVC_DIR, SERVICE_DIR, STARTED_SVC_DIR
|
||||
from .templates import SERVICE
|
||||
|
||||
def create_service(app, container, image):
|
||||
depends = ' '.join(image['depends']) if 'depends' in image else ''
|
||||
check = 'lxc-execute {} -- sh -c \'until $({}); do sleep 0.1; done\''.format(container, image['check']) if 'check' in image else ''
|
||||
with open(os.path.join(SERVICE_DIR, container), 'w') as f:
|
||||
f.write(SERVICE.format(app=app, container=container, depends=depends, check=check))
|
||||
update_services()
|
||||
|
||||
def delete_service(service):
|
||||
if is_service_started(service):
|
||||
stop_service(service)
|
||||
if is_service_autostarted(service):
|
||||
update_service_autostart(service, False)
|
||||
try:
|
||||
os.unlink(os.path.join(SERVICE_DIR, service))
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
update_services()
|
||||
|
||||
def update_services():
|
||||
subprocess.run(['/sbin/rc-update', '-u'], check=True)
|
||||
|
||||
def start_service(service):
|
||||
if not is_service_started(service):
|
||||
subprocess.run(['/sbin/service', service, 'stop'], check=True)
|
||||
|
||||
def stop_service(service):
|
||||
if is_service_started(service):
|
||||
subprocess.run(['/sbin/service', service, 'stop'], check=True)
|
||||
|
||||
def is_service_started(self, app):
|
||||
# Check OpenRC service status without calling any binary
|
||||
return os.path.exists(os.path.join(STARTED_SVC_DIR, app))
|
||||
|
||||
def is_service_autostarted(self, app):
|
||||
# Check OpenRC service enablement
|
||||
return os.path.exists(os.path.join(AUTOSTART_SVC_DIR, app))
|
||||
|
||||
def update_service_autostart(self, service, enabled):
|
||||
# Add/remove the app to OpenRC default runlevel
|
||||
subprocess.run(['/sbin/rc-update', 'add' if enabled else 'del', service])
|
@ -49,3 +49,24 @@ lxc.cap.drop = sys_admin
|
||||
lxc.include = /usr/share/lxc/config/common.conf
|
||||
lxc.include = /usr/share/lxc/config/userns.conf
|
||||
'''
|
||||
|
||||
SERVICE = """#!/sbin/openrc-run
|
||||
|
||||
description="{app} {container} LXC container"
|
||||
|
||||
depend() {{
|
||||
need cgroups {depends}
|
||||
}}
|
||||
|
||||
start() {{
|
||||
lxc-start {container}
|
||||
}}
|
||||
|
||||
start_post() {{
|
||||
{check}
|
||||
}}
|
||||
|
||||
stop() {{
|
||||
lxc-stop {container}
|
||||
}}
|
||||
"""
|
||||
|
@ -10,17 +10,6 @@ ACME_DIR = '/etc/acme.sh.d'
|
||||
CERT_KEY_FILE = '/etc/ssl/services.key'
|
||||
CERT_PUB_FILE = '/etc/ssl/services.pem'
|
||||
|
||||
# Package manager
|
||||
REPO_LOCAL_FILE = '/var/lib/lxc-pkg/packages'
|
||||
REPO_SIG_FILE = '/etc/vmmgr/packages.pub'
|
||||
REPO_CACHE_DIR = '/var/lib/lxc-pkg/cache'
|
||||
|
||||
# LXC
|
||||
HOSTS_FILE = '/etc/hosts'
|
||||
HOSTS_LOCK = '/var/lock/vmmgr-hosts.lock'
|
||||
LXC_ROOT = '/var/lib/lxc'
|
||||
LXC_STORAGE_DIR = '/var/lib/lxc-pkg/storage'
|
||||
|
||||
# OS
|
||||
ISSUE_FILE = '/etc/issue'
|
||||
MOTD_FILE = '/etc/motd'
|
||||
|
Loading…
Reference in New Issue
Block a user