89 lines
3.4 KiB
Python
89 lines
3.4 KiB
Python
"""用显式准备的私有 ARM 内核运行独立应用,不改主机服务或沙箱策略。"""
|
|
from pathlib import Path
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
import time
|
|
|
|
SOURCE = Path(__file__).resolve().parent
|
|
ROOT = SOURCE.parents[2] / "target/arm64-cross"
|
|
|
|
|
|
def prepare_images():
|
|
init = ROOT / "initramfs"
|
|
for source, destination in [
|
|
("init.sh", init / "init-arm"),
|
|
("bootstrap.sh", init / "init-stage"),
|
|
("guest.sh", ROOT / "guest/run.sh"),
|
|
]:
|
|
shutil.copyfile(SOURCE / source, destination)
|
|
destination.chmod(0o755)
|
|
archive = ROOT / "guest-initramfs.gz"
|
|
with archive.open("wb") as output:
|
|
with subprocess.Popen(
|
|
["/usr/bin/find", ".", "-print0"], cwd=init, stdout=subprocess.PIPE
|
|
) as find:
|
|
try:
|
|
with subprocess.Popen(
|
|
["/usr/bin/cpio", "--null", "-o", "--format=newc", "--quiet"],
|
|
cwd=init, stdin=find.stdout, stdout=subprocess.PIPE,
|
|
) as cpio:
|
|
find.stdout.close()
|
|
try:
|
|
subprocess.run(["/usr/bin/gzip", "-1"], stdin=cpio.stdout, stdout=output, check=True)
|
|
finally:
|
|
cpio.stdout.close()
|
|
finally:
|
|
find.stdout.close()
|
|
if find.returncode or cpio.returncode:
|
|
raise RuntimeError("initramfs creation failed")
|
|
disk = ROOT / "guest.ext4"
|
|
with disk.open("wb") as output:
|
|
output.truncate(1024 * 1024 * 1024)
|
|
subprocess.run(
|
|
["/usr/sbin/mke2fs", "-q", "-t", "ext4", "-F", "-d", str(ROOT / "guest"), str(disk)],
|
|
check=True,
|
|
)
|
|
return archive, disk
|
|
|
|
|
|
def main():
|
|
archive, disk = prepare_images()
|
|
command = [
|
|
"/lib64/ld-linux-x86-64.so.2", "--library-path",
|
|
str(ROOT / "tools/usr/lib/x86_64-linux-gnu"),
|
|
str(ROOT / "tools/usr/bin/qemu-system-aarch64"),
|
|
"-machine", "virt", "-cpu", "cortex-a72", "-smp", "2", "-m", "768",
|
|
"-nographic", "-no-reboot", "-nic", "none",
|
|
"-kernel", str(ROOT / "iso/boot/vmlinuz-virt"), "-initrd", str(archive),
|
|
"-append", "console=ttyAMA0 rdinit=/init-arm panic=-1",
|
|
"-drive", f"file={disk},format=raw,if=none,readonly=on,id=payload",
|
|
"-device", "virtio-blk-device,drive=payload",
|
|
]
|
|
log = ROOT / "logs" / f"guest-{time.time_ns()}.log"
|
|
started = time.monotonic()
|
|
timed_out = False
|
|
with log.open("xb") as output:
|
|
try:
|
|
result = subprocess.run(command, stdout=output, stderr=subprocess.STDOUT, timeout=600)
|
|
exit_code = result.returncode
|
|
except subprocess.TimeoutExpired:
|
|
timed_out = True
|
|
exit_code = None
|
|
transcript = log.read_text(errors="replace")
|
|
required = ["DEVER_ARM_GUEST_EXIT=0", "ARM_HTTP_PASS"]
|
|
required.extend(f"ARM_WORKER_PASS={ecosystem}" for ecosystem in ("pip", "npm", "go"))
|
|
passed = exit_code == 0 and all(marker in transcript for marker in required)
|
|
record = {
|
|
"command": command, "exit_code": exit_code, "timed_out": timed_out, "passed": passed,
|
|
"seconds": time.monotonic() - started, "log": str(log),
|
|
}
|
|
log.with_suffix(".json").write_text(json.dumps(record, indent=2) + "\n")
|
|
print(json.dumps(record), flush=True)
|
|
if not passed:
|
|
raise RuntimeError("ARM guest acceptance failed; see serial log")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|