2018-10-02 12:58:12 +02:00
|
|
|
#!/usr/bin/python3
|
|
|
|
|
|
|
|
import hashlib
|
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
|
2018-10-02 17:35:49 +02:00
|
|
|
from cryptography.hazmat.backends import default_backend
|
|
|
|
from cryptography.hazmat.primitives import hashes
|
|
|
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
|
|
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
|
|
|
|
2018-10-25 22:17:39 +02:00
|
|
|
BUILD_ROOT = '/srv/build/lxc'
|
|
|
|
PRIVATE_KEY = '/srv/build/packages.key'
|
2018-10-02 12:58:12 +02:00
|
|
|
LXC_ROOT = '/var/lib/lxc'
|
|
|
|
|
2018-10-02 17:35:49 +02:00
|
|
|
def pack(pkg_file):
|
2018-10-02 17:37:27 +02:00
|
|
|
if os.path.isdir(pkg_file):
|
2018-10-02 17:35:49 +02:00
|
|
|
pkg_file = os.path.join(pkg_file, 'pkg')
|
2018-10-02 12:58:12 +02:00
|
|
|
# Prepare metadata
|
|
|
|
meta = {}
|
2018-10-02 22:09:34 +02:00
|
|
|
with open(pkg_file) as f:
|
|
|
|
for line in f:
|
2018-10-02 12:58:12 +02:00
|
|
|
line = [l.strip() for l in line.split(':', 1)]
|
|
|
|
meta[line[0]] = line[1]
|
|
|
|
meta['deps'] = meta['deps'].split()
|
|
|
|
pkg_name = meta['pkg']
|
|
|
|
del meta['pkg']
|
|
|
|
|
|
|
|
tar_path = os.path.join(BUILD_ROOT, '{}.tar'.format(pkg_name))
|
|
|
|
xz_path = '{}.xz'.format(tar_path)
|
|
|
|
|
|
|
|
# Remove old package
|
2018-10-02 17:38:58 +02:00
|
|
|
if os.path.exists(tar_path):
|
2018-10-02 13:10:24 +02:00
|
|
|
os.unlink(tar_path)
|
2018-10-02 17:38:58 +02:00
|
|
|
if os.path.exists(xz_path):
|
2018-10-02 13:10:24 +02:00
|
|
|
os.unlink(xz_path)
|
2018-10-02 12:58:12 +02:00
|
|
|
|
|
|
|
# Create archive
|
|
|
|
print('Archiving', meta['lxcpath'])
|
2018-10-26 14:12:12 +02:00
|
|
|
subprocess.run(['tar', '--xattrs', '-cpf', tar_path, os.path.join(LXC_ROOT, meta['lxcpath'])], cwd='/')
|
2018-10-02 12:58:12 +02:00
|
|
|
if '/' not in meta['lxcpath']:
|
2018-10-26 14:12:12 +02:00
|
|
|
# If lxcpath doesn't point to layer but is a full-featured container, pack also scripts
|
|
|
|
print('Archiving install/upgrade/uninstall scripts and related files')
|
2018-10-02 17:35:49 +02:00
|
|
|
cwd = os.path.dirname(os.path.abspath(pkg_file))
|
2018-10-26 14:12:12 +02:00
|
|
|
subprocess.run(['tar', '--transform' 's,^\.,/srv/{},'.format(pkg_name), '-rpf', tar_path, 'install', 'install.sh', 'upgrade', 'upgrade.sh', 'uninstall', 'uninstall.sh'], cwd=cwd)
|
|
|
|
print('Compressing', tar_path, '({} MB)'.format(os.path.getsize(tar_path)/1048576))
|
2018-10-02 12:58:12 +02:00
|
|
|
subprocess.run(['xz', '-9', tar_path])
|
|
|
|
|
|
|
|
# Register package
|
|
|
|
print('Registering package')
|
|
|
|
packages = {}
|
|
|
|
packages_file = os.path.join(BUILD_ROOT, 'packages')
|
2018-10-02 17:38:58 +02:00
|
|
|
if os.path.exists(packages_file):
|
2018-10-02 22:09:34 +02:00
|
|
|
with open(packages_file, 'r') as f:
|
|
|
|
packages = json.load(f)
|
2018-10-02 12:58:12 +02:00
|
|
|
packages[pkg_name] = meta
|
2018-10-21 10:09:02 +02:00
|
|
|
packages[pkg_name]['size'] = os.path.getsize(xz_path)
|
2018-10-15 14:58:24 +02:00
|
|
|
packages[pkg_name]['sha512'] = hash_file(xz_path)
|
2018-10-02 22:09:34 +02:00
|
|
|
with open(packages_file, 'w') as f:
|
|
|
|
json.dump(packages, f, sort_keys=True, indent=4)
|
2018-10-02 12:58:12 +02:00
|
|
|
|
|
|
|
# Sign packages
|
|
|
|
print('Signing packages')
|
2018-10-25 22:17:39 +02:00
|
|
|
with open(PRIVATE_KEY, 'rb') as f:
|
2018-10-02 22:09:34 +02:00
|
|
|
priv_key = load_pem_private_key(f.read(), None, default_backend())
|
|
|
|
with open(os.path.join(BUILD_ROOT, 'packages'), 'rb') as f:
|
|
|
|
data = f.read()
|
|
|
|
with open(os.path.join(BUILD_ROOT, 'packages.sig'), 'wb') as f:
|
|
|
|
f.write(priv_key.sign(data, ec.ECDSA(hashes.SHA512())))
|
2018-10-02 12:58:12 +02:00
|
|
|
|
|
|
|
def hash_file(file_path):
|
|
|
|
sha512 = hashlib.sha512()
|
2018-10-02 22:09:34 +02:00
|
|
|
with open(file_path, 'rb') as f:
|
2018-10-02 12:58:12 +02:00
|
|
|
while True:
|
2018-10-02 22:09:34 +02:00
|
|
|
data = f.read(65536)
|
2018-10-02 12:58:12 +02:00
|
|
|
if not data:
|
|
|
|
break
|
|
|
|
sha512.update(data)
|
|
|
|
return sha512.hexdigest()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
if len(sys.argv) != 2:
|
|
|
|
print('Usage: lxc-pack <pkgfile>')
|
|
|
|
else:
|
|
|
|
pack(sys.argv[1])
|