Spotter-VM/build/usr/lib/python3.6/lxcbuild/packer.py

124 lines
4.8 KiB
Python
Raw Normal View History

2019-09-20 10:13:41 +02:00
# -*- coding: utf-8 -*-
import json
import os
import subprocess
import sys
from lxcmgr.paths import LXC_STORAGE_DIR
2019-09-20 15:43:01 +02:00
from lxcmgr.pkgmgr import PkgMgr
2019-09-20 10:13:41 +02:00
from . import crypto
2019-09-20 15:43:01 +02:00
from .builder import ImageNotFoundError
from .paths import PRIVATE_KEY, REPO_APPS_DIR, REPO_IMAGES_DIR, REPO_META_FILE, REPO_SIG_FILE
2019-09-20 10:13:41 +02:00
class PackageExistsError(Exception):
pass
class Packer:
def __init__(self):
self.app = None
self.image = None
self.tar_path = None
2019-09-24 10:04:13 +02:00
self.tar_size = 0
2019-09-20 10:13:41 +02:00
self.xz_path = None
2019-09-24 10:04:13 +02:00
self.xz_size = 0
2019-09-20 15:43:01 +02:00
if os.path.exists(REPO_META_FILE):
with open(REPO_META_FILE, 'r') as f:
self.packages = json.load(f)
2019-09-20 10:13:41 +02:00
else:
2019-09-20 15:43:01 +02:00
self.packages = {'apps': {}, 'images': {}}
2019-09-20 10:13:41 +02:00
2019-09-20 15:43:01 +02:00
def save_repo_meta(self):
with open(REPO_META_FILE, 'w') as f:
json.dump(self.packages, f, sort_keys=True, indent=4)
2019-09-20 10:13:41 +02:00
def pack_image(self, image, force):
self.image = image
# Prepare package file names
2019-09-20 15:43:01 +02:00
self.tar_path = os.path.join(REPO_IMAGES_DIR, '{}.tar'.format(self.image.name))
2019-09-20 10:13:41 +02:00
self.xz_path = '{}.xz'.format(self.tar_path)
2019-09-23 15:34:37 +02:00
if force:
self.unregister_image()
try:
2019-09-20 10:13:41 +02:00
os.unlink(self.xz_path)
2019-09-23 15:34:37 +02:00
except FileNotFoundError:
pass
elif os.path.exists(self.xz_path):
raise PackageExistsError(self.xz_path)
2019-09-20 10:13:41 +02:00
self.create_image_archive()
self.register_image()
self.sign_packages()
def create_image_archive(self):
# Create archive
print('Archiving', self.image.path)
subprocess.run(['tar', '--xattrs', '-cpf', self.tar_path, self.image.name], cwd=LXC_STORAGE_DIR)
self.compress_archive()
def compress_archive(self):
# Compress the tarball with xz (LZMA2)
2019-09-24 10:04:13 +02:00
self.tar_size = os.path.getsize(self.tar_path)
print('Compressing', self.tar_path, '({:.2f} MB)'.format(self.tar_size/1048576))
2019-09-20 10:13:41 +02:00
subprocess.run(['xz', '-9', self.tar_path])
2019-09-24 10:04:13 +02:00
self.xz_size = os.path.getsize(self.xz_path)
print('Compressed ', self.xz_path, '({:.2f} MB)'.format(self.xz_size/1048576))
2019-09-20 10:13:41 +02:00
def register_image(self):
2019-09-20 15:43:01 +02:00
# Register image in global repository metadata file
2019-09-20 10:13:41 +02:00
print('Registering package {}'.format(self.image.name))
2019-09-20 15:43:01 +02:00
self.packages['images'][self.image.name] = self.image.conf.copy()
2019-09-24 10:04:13 +02:00
self.packages['images'][self.image.name]['size'] = self.tar_size
self.packages['images'][self.image.name]['pkgsize'] = self.xz_size
2019-09-20 15:43:01 +02:00
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])
2019-09-20 10:13:41 +02:00
def sign_packages(self):
2019-09-20 15:43:01 +02:00
signature = crypto.sign_file(PRIVATE_KEY, REPO_META_FILE)
with open(REPO_SIG_FILE, 'wb') as f:
2019-09-20 10:13:41 +02:00
f.write(signature)
def unregister_image(self):
# Removes package from global repository metadata file
2019-09-20 15:43:01 +02:00
if self.image.name in self.packages['images']:
del self.packages['images'][self.image.name]
self.save_repo_meta()
2019-09-20 10:13:41 +02:00
def pack_app(self, app):
self.app = app
2019-09-20 15:43:01 +02:00
# 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)
2019-09-20 10:13:41 +02:00
# Prepare package file names
2019-09-20 15:43:01 +02:00
self.tar_path = os.path.join(REPO_APPS_DIR, '{}.tar'.format(self.app.name))
2019-09-20 10:13:41 +02:00
self.xz_path = '{}.xz'.format(self.tar_path)
2019-09-23 15:34:37 +02:00
try:
2019-09-20 10:13:41 +02:00
os.unlink(self.xz_path)
2019-09-23 15:34:37 +02:00
except FileNotFoundError:
pass
2019-09-20 10:13:41 +02:00
self.create_app_archive()
self.register_app()
self.sign_packages()
def create_app_archive(self):
# Create archive with application setup scripts
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))]
2019-09-20 15:43:01 +02:00
subprocess.run(['tar', '--xattrs', '-cpf', self.tar_path, '--transform', 's,^,{}/,'.format(self.app.name)] + scripts, cwd=self.app.build_dir)
2019-09-20 10:13:41 +02:00
self.compress_archive()
def register_app(self):
# Register package in global repository metadata file
print('Registering package {}'.format(self.app.name))
2019-09-20 15:43:01 +02:00
self.packages['apps'][self.app.name] = self.app.conf.copy()
2019-09-24 10:04:13 +02:00
self.packages['apps'][self.app.name]['size'] = self.tar_size
self.packages['apps'][self.app.name]['pkgsize'] = self.xz_size
2019-09-20 15:43:01 +02:00
self.packages['apps'][self.app.name]['sha512'] = crypto.hash_file(self.xz_path)
self.save_repo_meta()