Skip to content

Commit 323890e

Browse files
author
Andrea Righi
committed
virtme-ng: use pre-compiled mainline kernels
Allow to download precompiled mainline kernels from the Ubuntu mainline kernel repository (https://kernel.ubuntu.com/mainline). Mainline builds are provided by Ubuntu for debugging purposes, they are basically vanilla kernels (no additional patches applied), built with the generic Ubuntu .config and packaged as deb. These precompiled kernels can be used by virtme-ng to test specific mainline tags, without having to rebuild the kernel from source. To do so the option `--run` can now accept a Linux tag (i.e., v6.6-rc2). When a tag is specified, virtme-ng will search in the Ubuntu mainline repository and fetch the corresponding packages, if available. Packages are then cached and extracted inside $HOME/.cache/virtme-ng, so they just need to be downloaded the first time that a mainline tag is requested. Example usage: $ vng -r v6.6-rc2 -- uname -r 6.6.0-060600rc2-generic This allows to save even more time (and energy) when testing mainline kernel versions, completely cutting out the kernel rebuild time. Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
1 parent 4c65839 commit 323890e

File tree

4 files changed

+95
-15
lines changed

4 files changed

+95
-15
lines changed

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
argcomplete
2+
requests

virtme_ng/mainline.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# -*- mode: python -*-
2+
# Copyright 2023 Andrea Righi
3+
4+
"""virtme-ng: mainline kernel downloader."""
5+
6+
import os
7+
import re
8+
import sys
9+
import subprocess
10+
from glob import glob
11+
import requests
12+
from virtme_ng.utils import CACHE_DIR, spinner_decorator
13+
14+
BASE_URL = "https://kernel.ubuntu.com/mainline"
15+
16+
HTTP_CHUNK = 4096
17+
HTTP_TIMEOUT = 30
18+
19+
20+
class KernelDownloader:
21+
def __init__(self, version, arch="amd64", verbose=False):
22+
# Initialize cache directory
23+
self.kernel_dir = f"{CACHE_DIR}/{version}/{arch}"
24+
os.makedirs(self.kernel_dir, exist_ok=True)
25+
26+
# Fetch and extract precompiled mainline kernel
27+
self.target = f"{CACHE_DIR}/{version}/{arch}/boot/vmlinuz-*"
28+
if not glob(self.target):
29+
url = BASE_URL + "/" + version + "/" + arch
30+
if verbose:
31+
sys.stderr.write(f"use {version}/{arch} pre-compiled kernel from {url}\n")
32+
self._fetch_kernel(url)
33+
34+
def _download_file(self, url, destination):
35+
response = requests.get(url, stream=True, timeout=HTTP_TIMEOUT)
36+
if response.status_code == 200:
37+
with open(destination, 'wb') as file:
38+
for chunk in response.iter_content(chunk_size=HTTP_CHUNK):
39+
file.write(chunk)
40+
else:
41+
raise FileNotFoundError(f"failed to download {url}, error: {response.status_code}")
42+
43+
@spinner_decorator(message="📥 downloading kernel")
44+
def _fetch_kernel(self, url):
45+
response = requests.get(url, timeout=HTTP_TIMEOUT)
46+
if response.status_code == 200:
47+
href_pattern = re.compile(r'href=["\']([^\s"\']+.deb)["\']')
48+
matches = href_pattern.findall(response.text)
49+
for match in matches:
50+
# Skip headers packages
51+
if 'headers' in match:
52+
continue
53+
# Skip if package is already downloaded
54+
deb_file = f"{self.kernel_dir}/{match}"
55+
if os.path.exists(deb_file):
56+
continue
57+
self._download_file(url + "/" + match, deb_file)
58+
subprocess.check_call(['dpkg', '-x', deb_file, self.kernel_dir])
59+
if not glob(f"{self.kernel_dir}/*.deb"):
60+
raise FileNotFoundError(f"could not find kernel packages at {url}")
61+
else:
62+
raise FileNotFoundError(f"failed to retrieve content, error: {response.status_code}")

virtme_ng/run.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,11 @@ def autocomplete(*args, **kwargs):
2828
pass
2929

3030
from virtme.util import SilentError, uname, get_username
31-
from virtme_ng.utils import CONF_FILE
32-
from virtme_ng.spinner import Spinner
31+
from virtme_ng.utils import CONF_FILE, spinner_decorator
32+
from virtme_ng.mainline import KernelDownloader
3333
from virtme_ng.version import VERSION
3434

3535

36-
def spinner_decorator(message):
37-
def decorator(func):
38-
def wrapper(*args, **kwargs):
39-
with Spinner(message=message):
40-
result = func(*args, **kwargs)
41-
return result
42-
43-
return wrapper
44-
45-
return decorator
46-
47-
4836
def check_call_cmd(command, quiet=False, dry_run=False):
4937
if dry_run:
5038
print(" ".join(command))
@@ -776,7 +764,22 @@ def _get_virtme_overlay_rwdir(self, args):
776764

777765
def _get_virtme_run(self, args):
778766
if args.run is not None:
779-
self.virtme_param["kdir"] = "--kimg " + args.run
767+
# If an upstream version is specified (using an upstream tag) fetch
768+
# and run the corresponding kernel from the Ubuntu mainline
769+
# repository.
770+
if args.run.startswith('v'):
771+
if args.arch is None:
772+
arch = 'amd64'
773+
else:
774+
arch = args.arch
775+
try:
776+
mainline = KernelDownloader(args.run, arch=arch, verbose=args.verbose)
777+
self.virtme_param["kdir"] = "--kimg " + mainline.target
778+
except FileNotFoundError as exc:
779+
sys.stderr.write(str(exc) + "\n")
780+
sys.exit(1)
781+
else:
782+
self.virtme_param["kdir"] = "--kimg " + args.run
780783
else:
781784
self.virtme_param["kdir"] = "--kdir ./"
782785

virtme_ng/utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@
44
"""virtme-ng: configuration path."""
55

66
from pathlib import Path
7+
from virtme_ng.spinner import Spinner
78

9+
CACHE_DIR = Path(Path.home(), ".cache", "virtme-ng")
810
CONF_PATH = Path(Path.home(), ".config", "virtme-ng")
911
CONF_FILE = Path(CONF_PATH, "virtme-ng.conf")
12+
13+
14+
def spinner_decorator(message):
15+
def decorator(func):
16+
def wrapper(*args, **kwargs):
17+
with Spinner(message=message):
18+
result = func(*args, **kwargs)
19+
return result
20+
21+
return wrapper
22+
23+
return decorator

0 commit comments

Comments
 (0)