111 lines
3.7 KiB
Python
111 lines
3.7 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
import subprocess
|
||
|
|
import shutil
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
CHROOT_DIRECTORY = "/srv/chroot/ubuntu"
|
||
|
|
UBUNTU_RELEASE = "noble"
|
||
|
|
UBUNTU_MIRROR = "http://archive.ubuntu.com/ubuntu"
|
||
|
|
|
||
|
|
def execute_command(command, check=True, shell=False):
|
||
|
|
if shell:
|
||
|
|
return subprocess.run(command, shell=True, check=check)
|
||
|
|
return subprocess.run(command, check=check)
|
||
|
|
|
||
|
|
def initialize_chroot():
|
||
|
|
chroot_path = Path(CHROOT_DIRECTORY)
|
||
|
|
if chroot_path.exists() and list(chroot_path.iterdir()):
|
||
|
|
print(f"Chroot directory {CHROOT_DIRECTORY} already exists and is not empty.")
|
||
|
|
response = input("Reinitialize? This will delete everything. (yes/no): ")
|
||
|
|
if response.lower() != "yes":
|
||
|
|
print("Aborting.")
|
||
|
|
sys.exit(0)
|
||
|
|
shutil.rmtree(CHROOT_DIRECTORY)
|
||
|
|
|
||
|
|
if not shutil.which("debootstrap"):
|
||
|
|
print("Installing debootstrap...")
|
||
|
|
execute_command(["apt", "update"])
|
||
|
|
execute_command(["apt", "install", "-y", "debootstrap"])
|
||
|
|
|
||
|
|
if not shutil.which("systemd-nspawn"):
|
||
|
|
print("Installing systemd-container...")
|
||
|
|
execute_command(["apt", "update"])
|
||
|
|
execute_command(["apt", "install", "-y", "systemd-container"])
|
||
|
|
|
||
|
|
print(f"Creating chroot directory: {CHROOT_DIRECTORY}")
|
||
|
|
chroot_path.mkdir(parents=True, exist_ok=True)
|
||
|
|
|
||
|
|
print(f"Running debootstrap for {UBUNTU_RELEASE}...")
|
||
|
|
execute_command([
|
||
|
|
"debootstrap",
|
||
|
|
"--variant=minbase",
|
||
|
|
UBUNTU_RELEASE,
|
||
|
|
CHROOT_DIRECTORY,
|
||
|
|
UBUNTU_MIRROR
|
||
|
|
])
|
||
|
|
|
||
|
|
print("Configuring APT sources...")
|
||
|
|
sources_content = f"""deb {UBUNTU_MIRROR} {UBUNTU_RELEASE} main restricted universe multiverse
|
||
|
|
deb {UBUNTU_MIRROR} {UBUNTU_RELEASE}-updates main restricted universe multiverse
|
||
|
|
deb http://security.ubuntu.com/ubuntu {UBUNTU_RELEASE}-security main restricted universe multiverse
|
||
|
|
"""
|
||
|
|
(chroot_path / "etc/apt/sources.list").write_text(sources_content)
|
||
|
|
|
||
|
|
print("Setting hostname...")
|
||
|
|
(chroot_path / "etc/hostname").write_text("ubuntu-container\n")
|
||
|
|
|
||
|
|
print("Updating APT inside container...")
|
||
|
|
execute_command([
|
||
|
|
"systemd-nspawn",
|
||
|
|
"-D", CHROOT_DIRECTORY,
|
||
|
|
"--pipe",
|
||
|
|
"bash", "-c",
|
||
|
|
"export DEBIAN_FRONTEND=noninteractive && apt update"
|
||
|
|
])
|
||
|
|
|
||
|
|
print(f"\nContainer initialized successfully at {CHROOT_DIRECTORY}")
|
||
|
|
print(f"To enter: sudo python3 {sys.argv[0]}")
|
||
|
|
|
||
|
|
def enter_chroot():
|
||
|
|
chroot_path = Path(CHROOT_DIRECTORY)
|
||
|
|
if not chroot_path.exists() or not list(chroot_path.iterdir()):
|
||
|
|
print(f"Container not initialized. Run: sudo python3 {sys.argv[0]} init")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
if not shutil.which("systemd-nspawn"):
|
||
|
|
print("systemd-nspawn not found. Installing systemd-container...")
|
||
|
|
execute_command(["apt", "update"])
|
||
|
|
execute_command(["apt", "install", "-y", "systemd-container"])
|
||
|
|
|
||
|
|
print(f"Entering container at {CHROOT_DIRECTORY}...")
|
||
|
|
os.execvp("/usr/bin/systemd-nspawn", [
|
||
|
|
"systemd-nspawn",
|
||
|
|
"-D", CHROOT_DIRECTORY,
|
||
|
|
"--resolv-conf=bind-host",
|
||
|
|
"--private-users=pick",
|
||
|
|
"--drop-capability=CAP_SYS_MODULE,CAP_SYS_TIME,CAP_SYS_BOOT",
|
||
|
|
"--setenv=DEBIAN_FRONTEND=noninteractive"
|
||
|
|
])
|
||
|
|
|
||
|
|
def main():
|
||
|
|
if os.geteuid() != 0:
|
||
|
|
print("This script must be run as root (use sudo)")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
if len(sys.argv) == 1:
|
||
|
|
enter_chroot()
|
||
|
|
elif len(sys.argv) > 1:
|
||
|
|
match sys.argv[1]:
|
||
|
|
case "init":
|
||
|
|
initialize_chroot()
|
||
|
|
case _:
|
||
|
|
print(f"Unknown command: {sys.argv[1]}")
|
||
|
|
print(f"Usage: {sys.argv[0]} [init]")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|
||
|
|
|