Skip to content

Commit

Permalink
Merge pull request #75 from truenas/lock
Browse files Browse the repository at this point in the history
NAS-128183 / 24.10 / Allow running multiple installers (on different terminals). Introduce…
  • Loading branch information
themylogin authored Apr 3, 2024
2 parents e5ebabf + 6e87a2c commit 9795cc7
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 54 deletions.
35 changes: 5 additions & 30 deletions truenas_installer/__main__.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,13 @@
import os
import pathlib
import sys

import psutil

from ixhardware import parse_dmi

from .installer import Installer


if __name__ == "__main__":
pidfile = pathlib.Path("/run/truenas_installer.pid")
try:
pid = int(pidfile.read_text().strip())
except (FileNotFoundError, UnicodeDecodeError, ValueError):
pass
else:
try:
process = psutil.Process(pid)
except psutil.NoSuchProcess:
pass
else:
if "truenas_installer" in process.cmdline():
print(f"Installer is already running (pid={pid})", file=sys.stderr)
sys.exit(1)

pidfile.write_text(str(os.getpid()))
try:
with open("/etc/version") as f:
version = f.read().strip()
with open("/etc/version") as f:
version = f.read().strip()

dmi = parse_dmi()
dmi = parse_dmi()

installer = Installer(version, dmi)
installer.run()
finally:
pidfile.unlink(missing_ok=True)
installer = Installer(version, dmi)
installer.run()
7 changes: 7 additions & 0 deletions truenas_installer/exception.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
__all__ = ["InstallError"]


class InstallError(Exception):
def __init__(self, message):
self.message = message
super().__init__(message)
42 changes: 19 additions & 23 deletions truenas_installer/install.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
import os.path

import asyncio
import json
import os
import pathlib
import subprocess
import tempfile

from .exception import InstallError
from .lock import installation_lock
from .utils import get_partition, run

__all__ = ["InstallError", "install"]

BOOT_POOL = "boot-pool"


class InstallError(Exception):
def __init__(self, message):
self.message = message
super().__init__(message)


async def install(disks, create_swap, set_pmbr, authentication, sql, callback):
try:
if not os.path.exists("/etc/hostid"):
await run(["zgenhostid"])

for disk in disks:
callback(0, f"Formatting disk {disk}")
await format_disk(f"/dev/{disk}", create_swap, set_pmbr, callback)

callback(0, "Creating boot pool")
await create_boot_pool([get_partition(disk, 3) for disk in disks])
with installation_lock:
try:
await run_installer(disks, authentication, sql, callback)
finally:
await run(["zpool", "export", "-f", BOOT_POOL])
except subprocess.CalledProcessError as e:
raise InstallError(f"Command {' '.join(e.cmd)} failed:\n{e.stderr.rstrip()}")
if not os.path.exists("/etc/hostid"):
await run(["zgenhostid"])

for disk in disks:
callback(0, f"Formatting disk {disk}")
await format_disk(f"/dev/{disk}", create_swap, set_pmbr, callback)

callback(0, "Creating boot pool")
await create_boot_pool([get_partition(disk, 3) for disk in disks])
try:
await run_installer(disks, authentication, sql, callback)
finally:
await run(["zpool", "export", "-f", BOOT_POOL])
except subprocess.CalledProcessError as e:
raise InstallError(f"Command {' '.join(e.cmd)} failed:\n{e.stderr.rstrip()}")


async def format_disk(device, create_swap, set_pmbr, callback):
Expand Down
3 changes: 2 additions & 1 deletion truenas_installer/installer_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

from .dialog import dialog_checklist, dialog_menu, dialog_msgbox, dialog_password, dialog_yesno
from .disks import list_disks
from .install import InstallError, install
from .exception import InstallError
from .install import install
from .serial import serial_sql
from .swap import is_swap_safe

Expand Down
25 changes: 25 additions & 0 deletions truenas_installer/lock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import pathlib

from .exception import InstallError

__all__ = ["installation_lock"]


class InstallationLock:
def __init__(self):
self.path = pathlib.Path("/run/truenas_installer.lock")

def locked(self):
return self.path.exists()

def __enter__(self):
if self.locked():
raise InstallError("Installation is already in progress")

self.path.write_text("")

def __exit__(self, exc_type, exc_val, exc_tb):
self.path.unlink(missing_ok=True)


installation_lock = InstallationLock()

0 comments on commit 9795cc7

Please sign in to comment.