Skip to content

Commit 548da08

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 feature allows to save even more time (and energy) when testing mainline kernel versions, completely cutting the kernel rebuild time. Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
1 parent 5d6be91 commit 548da08

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

bin/virtme-pull-kernel

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env python
2+
#
3+
# TODO:
4+
# - download packages in parallel
5+
# - add a command to clean virtme-ng cache (e.g., `vng --clean-cache`)
6+
7+
import os
8+
import re
9+
import sys
10+
import requests
11+
import subprocess
12+
from glob import glob
13+
from pathlib import Path
14+
from virtme_ng.utils import CACHE_DIR
15+
16+
BASE_URL = "https://kernel.ubuntu.com/mainline"
17+
18+
def download_file(url, destination):
19+
response = requests.get(url, stream=True)
20+
if response.status_code == 200:
21+
with open(destination, 'wb') as file:
22+
for chunk in response.iter_content(chunk_size=4096):
23+
file.write(chunk)
24+
else:
25+
sys.stderr.write(f"failed to download {url}, error: {response.status_code}\n")
26+
sys.exit(1)
27+
28+
def extract_kernel():
29+
deb_files = [f for f in os.listdir('.') if f.endswith('.deb')]
30+
for deb_file in deb_files:
31+
subprocess.run(['dpkg', '-x', deb_file, "."])
32+
33+
def fetch_kernel(url):
34+
response = requests.get(url)
35+
if response.status_code == 200:
36+
href_pattern = re.compile(r'href=["\']([^\s"\']+.deb)["\']')
37+
matches = href_pattern.findall(response.text)
38+
for match in matches:
39+
# Skip headers packages
40+
if 'headers' in match:
41+
continue
42+
# Skip if package is already downloaded
43+
if os.path.exists(match):
44+
continue
45+
download_file(url + "/" + match, match)
46+
if not glob("*.deb"):
47+
sys.stderr.write(f"could not find kernel packages at {url}\n")
48+
sys.exit(1)
49+
else:
50+
sys.stderr.write(f"failed to retrieve content, error: {response.status_code}\n")
51+
sys.exit(1)
52+
53+
def main():
54+
version = sys.argv[1]
55+
arch = sys.argv[2]
56+
57+
kernel_dir = f"{CACHE_DIR}/{version}/{arch}"
58+
os.makedirs(kernel_dir, exist_ok=True)
59+
os.chdir(kernel_dir)
60+
fetch_kernel(BASE_URL + "/" + version + "/" + arch)
61+
extract_kernel()
62+
63+
if __name__ == '__main__':
64+
main()

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ def run(self):
153153
],
154154
scripts=[
155155
"bin/virtme-prep-kdir-mods",
156+
"bin/virtme-pull-kernel",
156157
],
157158
include_package_data=True,
158159
classifiers=[

virtme_ng/run.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
PIPE,
1919
CalledProcessError,
2020
)
21+
from glob import glob
2122
from select import select
2223
from pathlib import Path
2324
try:
@@ -28,7 +29,7 @@ def autocomplete(*args, **kwargs):
2829
pass
2930

3031
from virtme.util import SilentError, uname, get_username
31-
from virtme_ng.utils import CONF_FILE
32+
from virtme_ng.utils import CONF_FILE, CACHE_DIR
3233
from virtme_ng.spinner import Spinner
3334
from virtme_ng.version import VERSION
3435

@@ -776,7 +777,22 @@ def _get_virtme_overlay_rwdir(self, args):
776777

777778
def _get_virtme_run(self, args):
778779
if args.run is not None:
779-
self.virtme_param["kdir"] = "--kimg " + args.run
780+
# If an upstream version is specified (using an upstream tag) fetch
781+
# and run the corresponding kernel from the Ubuntu mainline
782+
# repository.
783+
if args.run.startswith('v'):
784+
if args.arch is None:
785+
arch = 'amd64'
786+
else:
787+
arch = args.arch
788+
target = f"{CACHE_DIR}/{args.run}/{arch}/boot/vmlinuz-*"
789+
if not glob(target):
790+
script = shutil.which('virtme-pull-kernel')
791+
print("downloading pre-compiled upstream kernel from Ubuntu mainline builds...")
792+
check_call_cmd([script, args.run, arch], quiet=not args.verbose, dry_run=args.dry_run)
793+
self.virtme_param["kdir"] = "--kimg " + target
794+
else:
795+
self.virtme_param["kdir"] = "--kimg " + args.run
780796
else:
781797
self.virtme_param["kdir"] = "--kdir ./"
782798

virtme_ng/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55

66
from pathlib import Path
77

8+
CACHE_DIR = Path(Path.home(), ".cache", "virtme-ng")
89
CONF_PATH = Path(Path.home(), ".config", "virtme-ng")
910
CONF_FILE = Path(CONF_PATH, "virtme-ng.conf")

0 commit comments

Comments
 (0)