2020-06-13 23:47:32 +00:00
|
|
|
import os
|
2020-11-06 14:44:47 +00:00
|
|
|
import subprocess
|
2021-06-25 21:45:59 +00:00
|
|
|
import tempfile
|
2020-06-13 23:47:32 +00:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
from util import run
|
|
|
|
|
|
|
|
|
|
|
|
def be_absent(path):
|
|
|
|
path = Path(path)
|
2021-01-16 00:04:43 +00:00
|
|
|
if path.is_symlink():
|
|
|
|
path.unlink()
|
|
|
|
elif path.is_file():
|
2020-06-13 23:47:32 +00:00
|
|
|
path.unlink()
|
|
|
|
elif path.is_dir():
|
|
|
|
path.rmdir()
|
|
|
|
# XXX: should we `shutil.rmtree(path)` instead?
|
2021-01-16 00:04:43 +00:00
|
|
|
elif not path.exists():
|
|
|
|
return
|
2020-06-13 23:47:32 +00:00
|
|
|
else:
|
|
|
|
raise Exception("Unknown file type")
|
|
|
|
|
|
|
|
|
|
|
|
def be_symlink(path, to):
|
|
|
|
path = Path(path)
|
|
|
|
to = Path(to)
|
2021-01-16 00:04:43 +00:00
|
|
|
if path.is_symlink():
|
|
|
|
if os.readlink(path) == str(to):
|
|
|
|
return
|
|
|
|
be_absent(path)
|
2020-06-13 23:47:32 +00:00
|
|
|
path.symlink_to(to)
|
|
|
|
|
|
|
|
|
|
|
|
def be_mounted(dev, mountpoint):
|
|
|
|
dev = Path(dev).resolve()
|
|
|
|
mountpoint = Path(mountpoint)
|
|
|
|
|
|
|
|
if mountpoint.is_mount():
|
|
|
|
if True: # TODO: verify that the right device is mounted
|
|
|
|
return
|
|
|
|
# noinspection PyUnreachableCode
|
|
|
|
be_unmounted(mountpoint)
|
|
|
|
|
2021-06-25 21:08:53 +00:00
|
|
|
fs = current_fs(dev)
|
|
|
|
if fs == "ext4":
|
|
|
|
run(f"mount {dev} {mountpoint}")
|
|
|
|
elif fs == "btrfs":
|
|
|
|
run(f"mount -o flushoncommit {dev} {mountpoint}")
|
2020-08-16 20:53:11 +00:00
|
|
|
elif fs == "xfs":
|
|
|
|
run(f"mount {dev} {mountpoint}")
|
2021-06-25 21:08:53 +00:00
|
|
|
else:
|
|
|
|
raise Exception(f"Unsupported fs type: {fs}")
|
2020-06-13 23:47:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
def be_unmounted(path):
|
|
|
|
path = Path(path)
|
|
|
|
while path.is_mount():
|
|
|
|
run(f"umount {path}")
|
2020-11-06 14:44:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
def current_fs(device):
|
|
|
|
res = subprocess.run(
|
|
|
|
f"blkid -o value -s TYPE {device}", shell=True, capture_output=True
|
|
|
|
)
|
|
|
|
if res.returncode == 2: # specified token was not found
|
|
|
|
return None
|
|
|
|
return res.stdout.decode().strip()
|
|
|
|
|
|
|
|
|
|
|
|
def be_formatted(dev, fs):
|
2021-06-25 21:07:52 +00:00
|
|
|
def init_fs(device):
|
2020-11-06 14:44:47 +00:00
|
|
|
if fs == "ext4":
|
2021-06-25 22:33:54 +00:00
|
|
|
run(f"mkfs.ext4 -m 0 {device}")
|
2020-11-06 14:44:47 +00:00
|
|
|
elif fs == "btrfs":
|
|
|
|
run(f"mkfs.btrfs {device}")
|
2021-06-25 21:45:59 +00:00
|
|
|
tmp_mnt = tempfile.mkdtemp(prefix="mnt-")
|
|
|
|
default_subvol = f"{tmp_mnt}/default"
|
|
|
|
run(
|
|
|
|
f"""
|
|
|
|
set -ex
|
|
|
|
mkdir -p {tmp_mnt}
|
|
|
|
mount {device} {tmp_mnt}
|
|
|
|
btrfs subvolume create {default_subvol}
|
|
|
|
btrfs subvolume set-default {default_subvol}
|
|
|
|
umount {tmp_mnt}
|
|
|
|
rmdir {tmp_mnt}
|
|
|
|
"""
|
|
|
|
)
|
2020-08-16 20:53:11 +00:00
|
|
|
elif fs == "xfs":
|
|
|
|
run(f"mkfs.xfs {device}")
|
2020-11-06 14:44:47 +00:00
|
|
|
else:
|
2021-06-25 21:07:52 +00:00
|
|
|
raise Exception(f"Unsupported fs type: {fs}")
|
2020-11-06 14:44:47 +00:00
|
|
|
|
|
|
|
dev = Path(dev).resolve()
|
|
|
|
current = current_fs(dev)
|
|
|
|
if current is None:
|
2021-06-25 21:07:52 +00:00
|
|
|
init_fs(dev)
|
2020-11-06 14:44:47 +00:00
|
|
|
else:
|
|
|
|
if current != fs:
|
|
|
|
raise Exception(f"Existing filesystem does not match: {current}/{fs}")
|
|
|
|
|
|
|
|
|
2021-06-25 21:07:52 +00:00
|
|
|
def be_fs_expanded(dev, path):
|
2020-11-06 14:44:47 +00:00
|
|
|
dev = Path(dev).resolve()
|
2021-06-25 21:07:52 +00:00
|
|
|
fs = current_fs(dev)
|
2020-11-06 14:44:47 +00:00
|
|
|
path = Path(path).resolve()
|
|
|
|
if fs == "ext4":
|
|
|
|
run(f"resize2fs {dev}")
|
|
|
|
elif fs == "btrfs":
|
|
|
|
run(f"btrfs filesystem resize max {path}")
|
2020-08-16 20:53:11 +00:00
|
|
|
elif fs == "xfs":
|
|
|
|
run(f"xfs_growfs -d {dev}")
|
2020-11-06 14:44:47 +00:00
|
|
|
else:
|
|
|
|
raise Exception(f"Unsupported fsType: {fs}")
|