mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-10 15:02:56 +00:00
Part of https://github.com/neondatabase/cloud/issues/13127. Resolves #9153 What changed in this PR: 1. Adds `ComputeSpec.disk_quota_bytes: Option<u64>` 2. Adds new arg to compute_ctl: `--set-disk-quota-for-fs <mountpoint>` 3. Implements running `/neonvm/bin/set-disk-quota` with the right value if both cmdline arg AND field in the spec are specified 4. Patches `/etc/sudoers.d` to allow `compute_ctl` to set quota with sudo This PR is very similar to the swap support added earlier, you can take a look at it as prior art: #7434 In theory, it can be implemented outside of compute_ctl when we will have a separate neonvm daemon, but we are not there yet. Current implementation is the simplest possible to unblock computes with larger disks. All code related to usage of `/neonvm/bin/set-disk-quota` is located in `disk_quota.rs`. We need to call this script with the following arguments: `/neonvm/bin/set-disk-quota {size_kb} {mountpoint}`. Quotas are set on the filesystem level, so we need to provide path to the directory that filesystem was mounted to. I tested this change locally with https://github.com/neondatabase/cloud/pull/17270. It should be safe to merge, because this feature is gated by both cmdline arg and field in the spec. If control-plane doesn't set values in both places, compute_ctl won't be affected by this change.
26 lines
1.1 KiB
Rust
26 lines
1.1 KiB
Rust
use anyhow::Context;
|
|
|
|
pub const DISK_QUOTA_BIN: &str = "/neonvm/bin/set-disk-quota";
|
|
|
|
/// If size_bytes is 0, it disables the quota. Otherwise, it sets filesystem quota to size_bytes.
|
|
/// `fs_mountpoint` should point to the mountpoint of the filesystem where the quota should be set.
|
|
pub fn set_disk_quota(size_bytes: u64, fs_mountpoint: &str) -> anyhow::Result<()> {
|
|
let size_kb = size_bytes / 1024;
|
|
// run `/neonvm/bin/set-disk-quota {size_kb} {mountpoint}`
|
|
let child_result = std::process::Command::new("/usr/bin/sudo")
|
|
.arg(DISK_QUOTA_BIN)
|
|
.arg(size_kb.to_string())
|
|
.arg(fs_mountpoint)
|
|
.spawn();
|
|
|
|
child_result
|
|
.context("spawn() failed")
|
|
.and_then(|mut child| child.wait().context("wait() failed"))
|
|
.and_then(|status| match status.success() {
|
|
true => Ok(()),
|
|
false => Err(anyhow::anyhow!("process exited with {status}")),
|
|
})
|
|
// wrap any prior error with the overall context that we couldn't run the command
|
|
.with_context(|| format!("could not run `/usr/bin/sudo {DISK_QUOTA_BIN}`"))
|
|
}
|