diff --git a/apk/vmmgr b/apk/vmmgr index c3b7118..4c26168 160000 --- a/apk/vmmgr +++ b/apk/vmmgr @@ -1 +1 @@ -Subproject commit c3b711850e02a6e228c4eb64ed82a4d1bc889ae9 +Subproject commit 4c2616887f52b1265aa5943d1b6bd0f7d5e9f008 diff --git a/build/usr/bin/lxcbuild b/build/usr/bin/lxcbuild index 6da06f8..cd60d72 100644 --- a/build/usr/bin/lxcbuild +++ b/build/usr/bin/lxcbuild @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- import argparse +import os import sys from lxcbuild.app import App from lxcbuild.image import Image @@ -37,7 +38,7 @@ else: image.build_and_pack(args.force) if os.path.exists(meta): valid_dir = True - app = App(buildpath) + app = App(meta) app.pack() if not valid_dir: print('Directory {} doesn\'t contain anything to build, skipping'.format(buildpath)) diff --git a/build/usr/lib/python3.6/lxcbuild/app.py b/build/usr/lib/python3.6/lxcbuild/app.py index d7ae2b4..b1dfe74 100644 --- a/build/usr/lib/python3.6/lxcbuild/app.py +++ b/build/usr/lib/python3.6/lxcbuild/app.py @@ -1,16 +1,26 @@ # -*- coding: utf-8 -*- +import json import os +import sys +from .builder import ImageNotFoundError from .packer import Packer class App: def __init__(self, metafile): self.build_dir = os.path.dirname(metafile) - self.name = os.path.basename(self.build_dir) + if os.path.basename(metafile) == 'meta': + self.name = os.path.basename(self.build_dir) + else: + self.name = os.path.splitext(metafile)[0] with open(metafile, 'r') as f: self.conf = json.load(f) def pack(self): packer = Packer() - packer.pack_app(self) + try: + packer.pack_app(self) + except ImageNotFoundError as e: + print('Image {} not found, can\'t pack {}'.format(e, self.name)) + sys.exit(1) diff --git a/build/usr/lib/python3.6/lxcbuild/builder.py b/build/usr/lib/python3.6/lxcbuild/builder.py index 652d38b..b6521a8 100644 --- a/build/usr/lib/python3.6/lxcbuild/builder.py +++ b/build/usr/lib/python3.6/lxcbuild/builder.py @@ -6,7 +6,7 @@ import subprocess import sys from lxcmgr import lxcmgr -from lxcmgr.paths import PKG_STORAGE_DIR +from lxcmgr.paths import LXC_STORAGE_DIR class ImageExistsError(Exception): pass @@ -63,10 +63,10 @@ class Builder: self.set_ready(args) def get_layer_path(self, layer): - return os.path.join(PKG_STORAGE_DIR, layer) + return os.path.join(LXC_STORAGE_DIR, layer) def run_script(self, script): - lxcmgr.register_container(self.image.name, self.image.conf) + lxcmgr.create_container(self.image.name, self.image.conf) sh = os.path.join(self.image.path, 'run.sh') with open(sh, 'w') as f: f.write('#!/bin/sh\nset -ev\n\n{}\n'.format('\n'.join(script))) @@ -74,7 +74,7 @@ class Builder: os.chown(sh, 100000, 100000) subprocess.run(['lxc-execute', self.image.name, '--', '/bin/sh', '-lc', '/run.sh'], check=True) os.unlink(sh) - lxcmgr.unregister_container(self.image.name) + lxcmgr.destroy_container(self.image.name) def set_name(self, name): self.image.name = name diff --git a/build/usr/lib/python3.6/lxcbuild/crypto.py b/build/usr/lib/python3.6/lxcbuild/crypto.py index fa94bde..44c27d2 100644 --- a/build/usr/lib/python3.6/lxcbuild/crypto.py +++ b/build/usr/lib/python3.6/lxcbuild/crypto.py @@ -7,10 +7,10 @@ from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import load_pem_private_key -def sign_file(private_key, input_path): +def sign_file(private_key_path, input_path): # Generate SHA512 signature of a file using EC private key print('Signing packages') - with open(private_key, 'rb') as f: + with open(private_key_path, 'rb') as f: priv_key = load_pem_private_key(f.read(), None, default_backend()) with open(input_path, 'rb') as f: data = f.read() diff --git a/build/usr/lib/python3.6/lxcbuild/packer.py b/build/usr/lib/python3.6/lxcbuild/packer.py index 737afe4..72c789d 100644 --- a/build/usr/lib/python3.6/lxcbuild/packer.py +++ b/build/usr/lib/python3.6/lxcbuild/packer.py @@ -6,9 +6,11 @@ import subprocess import sys from lxcmgr.paths import LXC_STORAGE_DIR +from lxcmgr.pkgmgr import PkgMgr from . import crypto -from .paths import APP_DIR, IMAGE_DIR, META_FILE, PRIVATE_KEY, ROOT_DIR, SIGNATURE_FILE +from .builder import ImageNotFoundError +from .paths import PRIVATE_KEY, REPO_APPS_DIR, REPO_IMAGES_DIR, REPO_META_FILE, REPO_SIG_FILE class PackageExistsError(Exception): pass @@ -19,23 +21,20 @@ class Packer: self.image = None self.tar_path = None self.xz_path = None - - def load_packages_meta(self): - if os.path.exists(PKG_META): - with open(PKG_META, 'r') as f: - return json.load(f) + if os.path.exists(REPO_META_FILE): + with open(REPO_META_FILE, 'r') as f: + self.packages = json.load(f) else: - return {'apps': {}, 'images': {}} - - def save_packages_meta(self, packages): - with open(PKG_META, 'w') as f: - json.dump(packages, f, sort_keys=True, indent=4) + self.packages = {'apps': {}, 'images': {}} + def save_repo_meta(self): + with open(REPO_META_FILE, 'w') as f: + json.dump(self.packages, f, sort_keys=True, indent=4) def pack_image(self, image, force): self.image = image # Prepare package file names - self.tar_path = os.path.join(IMAGE_DIR, '{}.tar'.format(self.image.name)) + self.tar_path = os.path.join(REPO_IMAGES_DIR, '{}.tar'.format(self.image.name)) self.xz_path = '{}.xz'.format(self.tar_path) if os.path.exists(self.xz_path): if force: @@ -60,30 +59,36 @@ class Packer: print('Compressed ', self.xz_path, '({:.2f} MB)'.format(os.path.getsize(self.xz_path)/1048576)) def register_image(self): - # Register package in global repository metadata file + # Register image in global repository metadata file print('Registering package {}'.format(self.image.name)) - packages = self.load_packages_meta() - packages['images'][self.image.name] = self.image.conf.copy() - packages['images'][self.image.name]['size'] = os.path.getsize(self.xz_path) - packages['images'][self.image.name]['sha512'] = crypto.hash_file(self.xz_path) - self.save_packages_meta(packages) + self.packages['images'][self.image.name] = self.image.conf.copy() + self.packages['images'][self.image.name]['size'] = os.path.getsize(self.xz_path) + self.packages['images'][self.image.name]['sha512'] = crypto.hash_file(self.xz_path) + self.save_repo_meta() + # Register the image also to locally installed images for package manager + pm = PkgMgr() + pm.register_image(self.image.name, self.packages['images'][self.image.name]) def sign_packages(self): - signature = crypto.sign_file(PRIVATE_KEY, META_FILE) - with open(SIGNATURE_FILE, 'wb') as f: + signature = crypto.sign_file(PRIVATE_KEY, REPO_META_FILE) + with open(REPO_SIG_FILE, 'wb') as f: f.write(signature) def unregister_image(self): # Removes package from global repository metadata file - packages = self.load_packages_meta() - if self.image.name in packages['images']: - del packages['images'][self.image.name] - self.save_packages_meta(packages) + if self.image.name in self.packages['images']: + del self.packages['images'][self.image.name] + self.save_repo_meta() def pack_app(self, app): self.app = app + # Check if all images exist + for container in app.conf['containers']: + image = app.conf['containers'][container]['image'] + if image not in self.packages['images']: + raise ImageNotFoundError(image) # Prepare package file names - self.tar_path = os.path.join(APP_DIR, '{}.tar'.format(self.image.name)) + self.tar_path = os.path.join(REPO_APPS_DIR, '{}.tar'.format(self.app.name)) self.xz_path = '{}.xz'.format(self.tar_path) if os.path.exists(self.xz_path): os.unlink(self.xz_path) @@ -96,14 +101,13 @@ class Packer: print('Archiving setup scripts for', self.app.name) scripts = ('install', 'install.sh', 'upgrade', 'upgrade.sh', 'uninstall', 'uninstall.sh') scripts = [s for s in scripts if os.path.exists(os.path.join(self.app.build_dir, s))] - subprocess.run(['tar', '--xattrs', '-cpf', self.tar_path] + scripts, cwd=self.app.build_dir) + subprocess.run(['tar', '--xattrs', '-cpf', self.tar_path, '--transform', 's,^,{}/,'.format(self.app.name)] + scripts, cwd=self.app.build_dir) self.compress_archive() def register_app(self): # Register package in global repository metadata file print('Registering package {}'.format(self.app.name)) - packages = self.load_packages_meta() - packages['apps'][self.image.name] = self.app.conf.copy() - packages['apps'][self.image.name]['size'] = os.path.getsize(self.xz_path) - packages['apps'][self.image.name]['sha512'] = crypto.hash_file(self.xz_path) - self.save_packages_meta(packages) + self.packages['apps'][self.app.name] = self.app.conf.copy() + self.packages['apps'][self.app.name]['size'] = os.path.getsize(self.xz_path) + self.packages['apps'][self.app.name]['sha512'] = crypto.hash_file(self.xz_path) + self.save_repo_meta() diff --git a/build/usr/lib/python3.6/lxcbuild/paths.py b/build/usr/lib/python3.6/lxcbuild/paths.py index bc1b8f9..bf4e455 100644 --- a/build/usr/lib/python3.6/lxcbuild/paths.py +++ b/build/usr/lib/python3.6/lxcbuild/paths.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- -ROOT_DIR = '/srv/build/lxc' -IMAGE_DIR = os.path.join(ROOT_DIR, 'images') -APP_DIR = os.path.join(ROOT_DIR, 'apps') -META_FILE = os.path.join(ROOT_DIR, 'packages') -SIGNATURE_FILE = os.path.join(ROOT_DIR, 'packages.sig') PRIVATE_KEY = '/srv/build/packages.key' +REPO_APPS_DIR = '/srv/build/lxc/apps' +REPO_IMAGES_DIR = '/srv/build/lxc/images' +REPO_META_FILE = '/srv/build/lxc/packages' +REPO_SIG_FILE = '/srv/build/lxc/packages.sig'