def NodeStageVolume(self, request, context): img_file = rawfile_util.img_file(request.volume_id) loop_file = attach_loop(img_file) staging_path = request.staging_target_path staging_dev_path = Path(f"{staging_path}/dev") be_symlink(path=staging_dev_path, to=loop_file) return csi_pb2.NodeStageVolumeResponse()
def NodeUnstageVolume(self, request, context): img_file = rawfile_util.img_file(request.volume_id) staging_path = request.staging_target_path staging_dev_path = Path(f"{staging_path}/dev") be_absent(staging_dev_path) detach_loops(img_file) return csi_pb2.NodeUnstageVolumeResponse()
def NodeStageVolume(self, request, context): img_file = rawfile_util.img_file(request.volume_id) loop_file = attach_loop(img_file) staging_path = request.staging_target_path device_path = Path(f"{staging_path}/device") be_symlink(path=device_path, to=loop_file) mount_path = Path(f"{staging_path}/mount") mount_path.mkdir(exist_ok=True) be_mounted(dev=device_path, mountpoint=mount_path) return csi_pb2.NodeStageVolumeResponse()
def NodeExpandVolume(self, request, context): volume_id = request.volume_id size = request.capacity_range.required_bytes img_file = rawfile_util.img_file(volume_id) for dev in rawfile_util.attached_loops(img_file): run(f"losetup -c {dev}") if True: # TODO: is ext2/ext3/ext4 run(f"resize2fs {dev}") break return csi_pb2.NodeExpandVolumeResponse(capacity_bytes=size)
def expand_rawfile(volume_id, size): import rawfile_util from util import run img_file = rawfile_util.img_file(volume_id) if rawfile_util.metadata(volume_id)["size"] >= size: return rawfile_util.patch_metadata( volume_id, {"size": size}, ) run(f"truncate -s {size} {img_file}")
def NodeExpandVolume(self, request, context): volume_id = request.volume_id volume_path = request.volume_path size = request.capacity_range.required_bytes fs_type = rawfile_util.metadata(volume_id)["fs_type"] img_file = rawfile_util.img_file(volume_id) for dev in rawfile_util.attached_loops(img_file): run(f"losetup -c {dev}") if fs_type == "ext4": run(f"resize2fs {dev}") elif fs_type == "btrfs": run(f"btrfs filesystem resize max {volume_path}") else: raise Exception(f"Unsupported fsType: {fs_type}") break return csi_pb2.NodeExpandVolumeResponse(capacity_bytes=size)
def collect(self): VOLUME_ID = "volume_id" fs_size = GaugeMetricFamily( "rawfile_filesystem_size_bytes", "Filesystem size in bytes.", labels=[VOLUME_ID], ) fs_free = GaugeMetricFamily( "rawfile_filesystem_avail_bytes", "Filesystem free space in bytes", labels=[VOLUME_ID], ) fs_files = GaugeMetricFamily( "rawfile_filesystem_files", "Filesystem total file nodes.", labels=[VOLUME_ID], ) fs_files_free = GaugeMetricFamily( "rawfile_filesystem_files_free", "Filesystem total free file nodes", labels=[VOLUME_ID], ) dev_size = GaugeMetricFamily("rawfile_device_size_bytes", "Device size in bytes.", labels=[VOLUME_ID]) dev_free = GaugeMetricFamily( "rawfile_device_free_bytes", "Device free space in bytes.", labels=[VOLUME_ID], ) for volume_id in rawfile_util.list_all_volumes(): img_file = rawfile_util.img_file(volume_id) labels = [volume_id] dev_stat = img_file.stat() dev_size.add_metric(labels, dev_stat.st_size) dev_free.add_metric(labels, dev_stat.st_size - dev_stat.st_blocks * 512) mountpoint = volume_to_mountpoint(img_file) if mountpoint is not None: fs_stat = os.statvfs(mountpoint) fs_size.add_metric(labels, fs_stat.f_frsize * fs_stat.f_blocks) fs_free.add_metric(labels, fs_stat.f_frsize * fs_stat.f_bfree) fs_files.add_metric(labels, fs_stat.f_files) fs_files_free.add_metric(labels, fs_stat.f_ffree) return [fs_size, fs_free, fs_files, fs_files_free, dev_size, dev_free]
def expand_rawfile(volume_id, size): import rawfile_util from util import run from consts import RESOURCE_EXHAUSTED_EXIT_CODE img_file = rawfile_util.img_file(volume_id) size_inc = size - rawfile_util.metadata(volume_id)["size"] if size_inc <= 0: return if rawfile_util.get_capacity() < size_inc: exit(RESOURCE_EXHAUSTED_EXIT_CODE) rawfile_util.patch_metadata( volume_id, {"size": size}, ) run(f"truncate -s {size} {img_file}")
def volume_stats(volume_id: str) -> dict: img_file = rawfile_util.img_file(volume_id) dev_stat = img_file.stat() stats = { "dev_size": dev_stat.st_size, "dev_free": dev_stat.st_size - dev_stat.st_blocks * 512, } mountpoint = volume_to_mountpoint(img_file) if mountpoint is not None: fs_stat = os.statvfs(mountpoint) stats.update( { "fs_size": fs_stat.f_frsize * fs_stat.f_blocks, "fs_free": fs_stat.f_frsize * fs_stat.f_bfree, "fs_files": fs_stat.f_files, "fs_files_free": fs_stat.f_ffree, } ) return stats
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)