1
0
Fork 0
mirror of https://github.com/containers/youki synced 2024-06-02 04:46:13 +02:00

Refactor and improve error reporting

This commit is contained in:
Yashodhan Joshi 2021-12-17 15:15:10 +05:30
parent d05bb63099
commit c40a306f87

View File

@ -3,7 +3,7 @@ use std::{
path::{Path, PathBuf},
};
use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use oci_spec::runtime::{
LinuxBlockIo, LinuxBlockIoBuilder, LinuxBuilder, LinuxResourcesBuilder,
LinuxThrottleDeviceBuilder, LinuxWeightDeviceBuilder, Spec, SpecBuilder,
@ -74,6 +74,33 @@ fn supports_throttle_iops() -> bool {
Path::new("/sys/fs/cgroup/blkio/blkio.throttle.read_iops_device").exists()
}
fn parse_device_data<'a>(device_type: &'static str, line: &'a str) -> Result<(i64, i64, &'a str)> {
let (device_id, value) = line
.split_once(" ")
.with_context(|| format!("invalid {} device format : found {}", device_type, line))?;
let (major_str, minor_str) = device_id.split_once(":").with_context(|| {
format!(
"invalid major-minor number format for {} device : found {}",
device_type, device_id
)
})?;
let major: i64 = major_str.parse().with_context(|| {
format!(
"Error in parsing {} device major number : found {}",
device_type, major_str
)
})?;
let minor: i64 = minor_str.parse().with_context(|| {
format!(
"Error in parsing {} device minor number : found {}",
device_type, minor_str
)
})?;
Ok((major, minor, value))
}
fn create_spec(cgroup_name: &str, block_io: LinuxBlockIo) -> Result<Spec> {
let spec = SpecBuilder::default()
.linux(
@ -95,65 +122,81 @@ fn create_spec(cgroup_name: &str, block_io: LinuxBlockIo) -> Result<Spec> {
}
/// parses /sys/fs/cgroup/blkio and creates BlockIO struct
fn get_blkio_data(path: &str) -> Result<BlockIO> {
fn get_blkio_data(path: &Path) -> Result<BlockIO> {
let mut device = BlockIO::default();
// we assume that if weight is present, leaf_weight will also be present
if supports_weight() {
// weight
let weight_string = fs::read_to_string(format!("{}/blkio.weight", path))
.context("error in reading block io weight")?;
device.weight = weight_string
.parse()
.context("error in parsing block io weight")?;
let weight_path = path.join("blkio.weight");
let weight_string = fs::read_to_string(&weight_path)
.with_context(|| format!("error in reading block io weight from {:?}", weight_path))?;
device.weight = weight_string.parse().with_context(|| {
format!("error in parsing block io weight : found {}", weight_string)
})?;
// leaf weight
let leaf_weight_string = fs::read_to_string(format!("{}/blkio.leaf_weight", path))
.context("error in reading block io leaf weight")?;
device.leaf_weight = leaf_weight_string
.parse()
.context("error in parsing block io weight")?;
let leaf_weight_path = path.join("blkio.leaf_weight");
let leaf_weight_string = fs::read_to_string(&leaf_weight_path).with_context(|| {
format!(
"error in reading block io leaf weight from {:?}",
leaf_weight_path
)
})?;
device.leaf_weight = leaf_weight_string.parse().with_context(|| {
format!(
"error in parsing block io weight : found {}",
leaf_weight_string
)
})?;
}
// weight devices section ------------
// we assume if device_weight is supported, then device_leaf_weight is also supported
if supports_weight_devices() {
// device weight
let device_weight_string = fs::read_to_string(format!("{}/blkio.weight_device", path))
.context("error in reading block io weight device")?;
let device_weight_path = path.join("blkio.weight_device");
let device_weight_string = fs::read_to_string(&device_weight_path).with_context(|| {
format!(
"error in reading block io weight device from {:?}",
device_weight_path
)
})?;
let mut weight_devices = Vec::new();
// format is <major>:<minor> <bytes_per_second>
for line in device_weight_string.lines() {
let (device_data, weight) = line
.split_once(" ")
.context("invalid weight device format")?;
let (major_str, minor_str) = device_data
.split_once(":")
.context("invalid major-minor number format")?;
let (major, minor, weight_str) = parse_device_data("weight", line)?;
weight_devices.push(WeightDevice {
major: major_str.parse().context("error in parsing major number")?,
minor: minor_str.parse().context("error in parsing minor number")?,
weight: Some(weight.parse().context("error in parsing weight")?),
major,
minor,
weight: Some(weight_str.parse().with_context(|| {
format!(
"error in parsing weight of weight device, found {}",
weight_str
)
})?),
leaf_weight: None,
});
}
// device leaf weight
let device_leaf_weight_path = path.join("blkio.leaf_weight_device");
let device_leaf_weight_string =
fs::read_to_string(format!("{}/blkio.leaf_weight_device", path))
.context("error in reading block io leaf weight device")?;
fs::read_to_string(&device_leaf_weight_path).with_context(|| {
format!(
"error in reading block io leaf weight device from {:?}",
device_leaf_weight_path
)
})?;
for line in device_leaf_weight_string.lines() {
let (device_data, weight) = line
.split_once(" ")
.context("invalid weight device format")?;
let (major_str, minor_str) = device_data
.split_once(":")
.context("invalid major-minor number format")?;
let leaf_weight: u16 = weight.parse().context("error in parsing leaf weight")?;
let major: i64 = major_str.parse().context("error in parsing major number")?;
let minor: i64 = minor_str.parse().context("error in parsing minor number")?;
let (major, minor, weight_str) = parse_device_data("weight", line)?;
let leaf_weight: u16 = weight_str.parse().with_context(|| {
format!(
"error in parsing leaf weight of weight device : found {}",
weight_str
)
})?;
let mut found = false;
for dev in &mut weight_devices {
if dev.major == major && dev.minor == minor {
@ -179,46 +222,51 @@ fn get_blkio_data(path: &str) -> Result<BlockIO> {
// we assume that if read_bps is supported, write_bps is also supported
if supports_throttle_bps() {
// throttle read bps
let throttle_read_bps_path = path.join("blkio.throttle.read_bps_device");
let throttle_read_bps_string =
fs::read_to_string(format!("{}/blkio.throttle.read_bps_device", path))
.context("error in reading block io write bps device")?;
fs::read_to_string(&throttle_read_bps_path).with_context(|| {
format!(
"error in reading block io read bps device from {:?}",
throttle_read_bps_path
)
})?;
let mut throttle_devices = Vec::new();
for line in throttle_read_bps_string.lines() {
let (device_data, rate) = line
.split_once(" ")
.context("invalid weight device format")?;
let (major_str, minor_str) = device_data
.split_once(":")
.context("invalid major-minor number format")?;
let (major, minor, rate_str) = parse_device_data("throttle read bps", line)?;
throttle_devices.push(ThrottleDevice {
major: major_str.parse().context("error in parsing major number")?,
minor: minor_str.parse().context("error in parsing minor number")?,
rate: rate
.parse()
.context("error in parsing throttle read bps rate")?,
major,
minor,
rate: rate_str.parse().with_context(|| {
format!(
"error in parsing throttle read bps rate : found {}",
rate_str
)
})?,
});
}
device.throttle_read_bps_devices = throttle_devices;
// throttle write bps
let throttle_write_bps_path = path.join("blkio.throttle.write_bps_device");
let throttle_write_bps_string =
fs::read_to_string(format!("{}/blkio.throttle.write_bps_device", path))
.context("error in reading block io write bps device")?;
fs::read_to_string(&throttle_write_bps_path).with_context(|| {
format!(
"error in reading block io write bps device from {:?}",
throttle_write_bps_path
)
})?;
let mut throttle_devices = Vec::new();
for line in throttle_write_bps_string.lines() {
let (device_data, rate) = line
.split_once(" ")
.context("invalid weight device format")?;
let (major_str, minor_str) = device_data
.split_once(":")
.context("invalid major-minor number format")?;
let (major, minor, rate_str) = parse_device_data("throttle write bps", line)?;
throttle_devices.push(ThrottleDevice {
major: major_str.parse().context("error in parsing major number")?,
minor: minor_str.parse().context("error in parsing minor number")?,
rate: rate
.parse()
.context("error in parsing throttle write bps rate")?,
major,
minor,
rate: rate_str.parse().with_context(|| {
format!(
"error in parsing throttle write bps rate : found {}",
rate_str
)
})?,
});
}
device.throttle_write_bps_devices = throttle_devices;
@ -227,47 +275,51 @@ fn get_blkio_data(path: &str) -> Result<BlockIO> {
// we assume that is read_iops is supported, write_iops is also supported
if supports_throttle_iops() {
// throttle read iops
let throttle_read_iops_path = path.join("blkio.throttle.read_iops_device");
let throttle_read_iops_string =
fs::read_to_string(format!("{}/blkio.throttle.read_iops_device", path))
.context("error in reading block io read iops device")?;
fs::read_to_string(&throttle_read_iops_path).with_context(|| {
format!(
"error in reading block io read iops device from {:?}",
throttle_read_iops_path
)
})?;
let mut throttle_devices = Vec::new();
for line in throttle_read_iops_string.lines() {
let (device_data, rate) = line
.split_once(" ")
.context("invalid throttle device format")?;
let (major_str, minor_str) = device_data
.split_once(":")
.context("invalid major-minor number format")?;
let (major, minor, rate_str) = parse_device_data("throttle read iops", line)?;
throttle_devices.push(ThrottleDevice {
major: major_str.parse().context("error in parsing major number")?,
minor: minor_str.parse().context("error in parsing minor number")?,
rate: rate
.parse()
.context("error in parsing throttle read iops rate")?,
major,
minor,
rate: rate_str.parse().with_context(|| {
format!(
"error in parsing throttle read iops rate : found {}",
rate_str
)
})?,
});
}
device.throttle_read_iops_devices = throttle_devices;
// throttle write iops
let throttle_write_iops_string =
fs::read_to_string(format!("{}/blkio.throttle.write_iops_device", path))
.context("error in reading block io write iops device")?;
let throttle_write_iops_path = path.join("blkio.throttle.write_iops_device");
let throttle_write_iops_string = fs::read_to_string(&throttle_write_iops_path)
.with_context(|| {
format!(
"error in reading block io write iops device from {:?}",
throttle_write_iops_path
)
})?;
let mut throttle_devices = Vec::new();
for line in throttle_write_iops_string.lines() {
let (device_data, rate) = line
.split_once(" ")
.context("invalid throttle device format")?;
let (major_str, minor_str) = device_data
.split_once(":")
.context("invalid major-minor number format")?;
let (major, minor, rate_str) = parse_device_data("throttle write iop", line)?;
throttle_devices.push(ThrottleDevice {
major: major_str.parse().context("error in parsing major number")?,
minor: minor_str.parse().context("error in parsing minor number")?,
rate: rate
.parse()
.context("error in parsing throttle write iops rate")?,
major,
minor,
rate: rate_str.parse().with_context(|| {
format!(
"error in parsing throttle write iops rate : found {}",
rate_str
)
})?,
});
}
device.throttle_write_iops_devices = throttle_devices;
@ -282,31 +334,31 @@ fn validate_block_io(cgroup_name: &str, spec: &Spec) -> Result<()> {
let cgroup_path = PathBuf::from(CGROUP_ROOT)
.join("blkio/runtime-test")
.join(cgroup_name);
let block_io = get_blkio_data(cgroup_path.to_str().unwrap())?;
let block_io = get_blkio_data(&cgroup_path)?;
let resources = spec.linux().as_ref().unwrap().resources().as_ref().unwrap();
let spec_block_io = resources.block_io().as_ref().unwrap();
// weight ------
if supports_weight() {
if spec_block_io.weight().is_none() {
return Err(anyhow::anyhow!("spec block io weight is none"));
bail!("spec block io weight is none");
}
if spec_block_io.weight().unwrap() != block_io.weight {
return Err(anyhow::anyhow!(
bail!(
"block io weight is set incorrectly, expected {}, actual {}",
spec_block_io.weight().unwrap(),
block_io.weight,
));
);
}
if spec_block_io.leaf_weight().is_none() {
return Err(anyhow::anyhow!("spec block io leaf weight is none"));
bail!("spec block io leaf weight is none");
}
if spec_block_io.leaf_weight().unwrap() != block_io.leaf_weight {
return Err(anyhow::anyhow!(
bail!(
"block io leaf weight is set incorrectly, expected {}, actual {}",
spec_block_io.leaf_weight().unwrap(),
block_io.leaf_weight,
));
);
}
}
@ -320,32 +372,32 @@ fn validate_block_io(cgroup_name: &str, spec: &Spec) -> Result<()> {
if device.major == spec_major && device.minor == spec_minor {
found = true;
if device.weight != spec_device.weight() {
return Err(anyhow::anyhow!(
bail!(
"blkio weight is set incorrectly for device {}:{}, expected {:?}, found {:?}",
spec_major,
spec_minor,
spec_device.weight(),
device.weight
));
);
}
if device.leaf_weight != spec_device.leaf_weight() {
return Err(anyhow::anyhow!(
bail!(
"blkio leaf weight is set incorrectly for device {}:{}, expected {:?}, found {:?}",
spec_major,
spec_minor,
spec_device.leaf_weight(),
device.leaf_weight
));
);
}
break;
}
}
if !found {
return Err(anyhow::anyhow!(
bail!(
"blkio weight device {}:{} not found, exists in spec",
spec_major,
spec_minor
));
);
}
}
}
@ -359,23 +411,23 @@ fn validate_block_io(cgroup_name: &str, spec: &Spec) -> Result<()> {
if device.major == spec_major && device.minor == spec_minor {
found = true;
if device.rate != spec_device.rate() {
return Err(anyhow::anyhow!(
bail!(
"blkio throttle read bps rate is set incorrectly for device {}:{}, expected {}, found {}",
spec_major,
spec_minor,
spec_device.rate(),
device.rate
));
);
}
break;
}
}
if !found {
return Err(anyhow::anyhow!(
bail!(
"blkio throttle read bps device {}:{} not found, exists in spec",
spec_major,
spec_minor
));
);
}
}
for spec_device in spec_block_io.throttle_write_bps_device().as_ref().unwrap() {
@ -386,23 +438,23 @@ fn validate_block_io(cgroup_name: &str, spec: &Spec) -> Result<()> {
if device.major == spec_major && device.minor == spec_minor {
found = true;
if device.rate != spec_device.rate() {
return Err(anyhow::anyhow!(
bail!(
"blkio throttle write bps rate is set incorrectly for device {}:{}, expected {}, found {}",
spec_major,
spec_minor,
spec_device.rate(),
device.rate
));
);
}
break;
}
}
if !found {
return Err(anyhow::anyhow!(
bail!(
"blkio throttle write bps device {}:{} not found, exists in spec",
spec_major,
spec_minor
));
);
}
}
}
@ -417,23 +469,23 @@ fn validate_block_io(cgroup_name: &str, spec: &Spec) -> Result<()> {
if device.major == spec_major && device.minor == spec_minor {
found = true;
if device.rate != spec_device.rate() {
return Err(anyhow::anyhow!(
bail!(
"blkio throttle read iops rate is set incorrectly for device {}:{}, expected {}, found {}",
spec_major,
spec_minor,
spec_device.rate(),
device.rate
));
);
}
break;
}
}
if !found {
return Err(anyhow::anyhow!(
bail!(
"blkio throttle read iops device {}:{} not found, exists in spec",
spec_major,
spec_minor
));
);
}
}
@ -445,23 +497,23 @@ fn validate_block_io(cgroup_name: &str, spec: &Spec) -> Result<()> {
if device.major == spec_major && device.minor == spec_minor {
found = true;
if device.rate != spec_device.rate() {
return Err(anyhow::anyhow!(
bail!(
"blkio throttle write iops rate is set incorrectly for device {}:{}, expected {}, found {}",
spec_major,
spec_minor,
spec_device.rate(),
device.rate
));
);
}
break;
}
}
if !found {
return Err(anyhow::anyhow!(
bail!(
"blkio throttle write iops device {}:{} not found, exists in spec",
spec_major,
spec_minor
));
);
}
}
}