rawfile-localpv/remote.py

132 lines
3.4 KiB
Python

from contextlib import contextmanager
from util import remote_fn
def scrub(volume_id):
import time
from subprocess import CalledProcessError
import rawfile_util
from consts import VOLUME_IN_USE_EXIT_CODE
img_dir = rawfile_util.img_dir(volume_id)
if not img_dir.exists():
return
img_file = rawfile_util.img_file(volume_id)
loops = rawfile_util.attached_loops(img_file)
if len(loops) > 0:
raise CalledProcessError(returncode=VOLUME_IN_USE_EXIT_CODE, cmd="")
now = time.time()
deleted_at = now
gc_at = now # TODO: GC sensitive PVCs later
rawfile_util.patch_metadata(volume_id, {"deleted_at": deleted_at, "gc_at": gc_at})
rawfile_util.gc_if_needed(volume_id, dry_run=False)
def init_rawfile(volume_id, size):
import time
from subprocess import CalledProcessError
from pathlib import Path
import rawfile_util
from volume_schema import LATEST_SCHEMA_VERSION
from util import run
img_dir = rawfile_util.img_dir(volume_id)
img_dir.mkdir(exist_ok=True)
img_file = Path(f"{img_dir}/disk.img")
if img_file.exists():
return
rawfile_util.patch_metadata(
volume_id,
{
"schema_version": LATEST_SCHEMA_VERSION,
"volume_id": volume_id,
"created_at": time.time(),
"img_file": img_file.as_posix(),
"size": size,
},
)
run(f"truncate -s {size} {img_file}")
def get_capacity():
import rawfile_util
cap = rawfile_util.get_capacity()
return max(0, cap)
@remote_fn
def expand_rawfile(volume_id, size):
import rawfile_util
from util import run
img_file = rawfile_util.img_file(volume_id)
size_inc = size - rawfile_util.metadata(volume_id)["size"]
if size_inc <= 0:
return
rawfile_util.patch_metadata(
volume_id,
{"size": size},
)
run(f"truncate -s {size} {img_file}")
@contextmanager
def mount_root_subvol(volume_id):
import tempfile
import pathlib
import rawfile_util
from util import run
root_subvol = tempfile.mkdtemp(prefix="rawfile-")
img_file = rawfile_util.img_file(volume_id)
loop_dev = rawfile_util.attach_loop(img_file)
run(f"mount -t btrfs -o subvolid=0 {loop_dev} {root_subvol}")
try:
yield root_subvol
finally:
run(f"umount {root_subvol}")
pathlib.Path(root_subvol).rmdir()
def btrfs_delete_snapshot(volume_id, name):
import btrfsutil
with mount_root_subvol(volume_id) as root_subvol:
snapshots_dir = f"{root_subvol}/.snapshots"
snapshot_path = f"{snapshots_dir}/{name}"
btrfsutil.delete_subvolume(snapshot_path)
def btrfs_create_snapshot(volume_id, name):
import btrfsutil
import time
import pathlib
# TODO: check fstype
with mount_root_subvol(volume_id) as root_subvol:
default_subvol_id = btrfsutil.get_default_subvolume(root_subvol)
default_subvol = btrfsutil.subvolume_path(root_subvol, default_subvol_id)
default_subvol = f"{root_subvol}/{default_subvol}"
snapshots_dir = f"{root_subvol}/.snapshots"
pathlib.Path(snapshots_dir).mkdir(parents=True, exist_ok=True)
snapshot_subvol = f"{snapshots_dir}/{name}"
btrfsutil.create_snapshot(default_subvol, snapshot_subvol, read_only=True)
snapshot_id = f"{volume_id}/{name}"
creation_time_ns = time.time_ns()
return snapshot_id, creation_time_ns