blob: 5a3e5ee21d5067eaa3218d9129dab12963540086 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Uprevs Termina images"""
import argparse
import json
import os
import shutil
import struct
import subprocess
import sys
import tempfile
import urllib.request
from pathlib import Path
from termina_build_image import repack_rootfs
from termina_util import mount_disk, get_release_version
def download_image(board, build, branch, output_dir):
image_archive_url = 'https://storage.googleapis.com/chromeos-image-archive'
build_config_format = '{}-full'
if branch:
build_config_format = '{}-full-tryjob'
build_config = build_config_format.format(board)
# Manually specified builds override branches.
build_version = 'master'
if branch:
build_version = branch
if build:
build_version = build
base_url = '{}/{}'.format(image_archive_url, build_config)
symlink_url = '{}/LATEST-{}'.format(base_url, build_version)
print("Checking symlink URL", symlink_url)
response = urllib.request.urlopen(symlink_url)
build_number = response.read().decode('utf-8')
image_url = '{}/{}/chromiumos_base_image.tar.xz'.format(base_url, build_number)
print('Downloading image from', image_url)
target_path = output_dir / '{}_base_image.tar.xz'.format(board)
filename, headers = urllib.request.urlretrieve(image_url, str(target_path))
print('Image downloaded to', filename)
return filename
def build_component(board, image_path, output_dir, component_version):
component_dir = output_dir / board
component_dir.mkdir()
result = subprocess.run(['tar', 'xvf', image_path, '-C', str(component_dir)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
print('Repacking rootfs')
repack_rootfs(component_dir, component_dir / 'chromiumos_base_image.bin')
# Assemble the component disk image.
print('Building component disk image')
component_disk = component_dir / 'image.ext4'
with component_disk.open('wb+') as component:
component.truncate(300 * 1024 * 1024)
subprocess.run(['/sbin/mkfs.ext4', '-b', '4096', '-O', '^has_journal', str(component_disk)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
mnt_dir = component_dir / 'mnt'
mnt_dir.mkdir()
with mount_disk(str(component_disk), str(mnt_dir)) as mntpoint:
for component_file in ['about_os_credits.html', 'lsb-release', 'vm_kernel', 'vm_rootfs.img']:
shutil.copy(str(component_dir / component_file), str(mnt_dir / component_file))
subprocess.run(['/sbin/e2fsck', '-y', '-f', str(component_disk)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
subprocess.run(['/sbin/resize2fs', '-M', str(component_disk)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
# Create manifest and zip up.
print('Zipping up component and manifest')
release_version = get_release_version(component_dir / 'lsb-release')
if not release_version:
print("No valid version in lsb-release")
sys.exit(1)
manifest_contents = {
'description': 'Chrome OS VM Container',
'name': 'termina',
'version': release_version,
'min_env_version': component_version,
'squash' : 'false',
'image_name' : 'image.ext4',
'fs_type' : 'ext4',
'is_removable' : 'true'
}
manifest_encoded = json.dumps(manifest_contents)
manifest_path = component_dir / 'manifest.json'
with open(str(manifest_path), 'w+') as manifest:
manifest.write(manifest_encoded)
subprocess.run(['zip', '-rj', str(component_dir / 'files.zip'), str(component_disk), str(manifest_path)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
def main():
parser = argparse.ArgumentParser(description='Uprev Termina images')
parser.add_argument('--build', help='build number, e.g. 11396.0.0 (default: master)')
parser.add_argument('--branch', help='optional branch name, e.g. release-R72-11316.B (default: master)')
parser.add_argument('--output_dir', help='local dir to save results')
parser.add_argument('component_version', help='version of the component')
args = parser.parse_args()
if os.geteuid() != 0:
print('this script must be run as root')
sys.exit(1)
with tempfile.TemporaryDirectory() as tempdir_path:
tempdir = Path(tempdir_path)
for board in ['tatl', 'tael']:
image_path = download_image(board, args.build, args.branch, tempdir)
build_component(board, image_path, tempdir, args.component_version)
if args.output_dir:
target_dir = Path(args.output_dir) / board
shutil.copytree(str(tempdir / board), str(target_dir))
sys.exit(0)
if __name__ == '__main__':
main()