From 59de6f644def5555c41e2ef14317e9178c40259f Mon Sep 17 00:00:00 2001 From: Yuhang Wei Date: Wed, 27 Nov 2024 18:34:14 +0000 Subject: [PATCH 03/11] fix(os-agent): use findmnt to find out which device mounted on / use "findmnt -no SOURCE --mountpoint /" to get the device name mounted on / use "lsblk -blno FSTYPE,SIZE" to get the fstype and partition size This patch fixes the problem if there are multiple mountpoints on a device Signed-off-by: Yuhang Wei --- KubeOS-Rust/manager/src/sys_mgmt/config.rs | 21 ++---- KubeOS-Rust/manager/src/utils/partition.rs | 86 +++++++++------------- 2 files changed, 41 insertions(+), 66 deletions(-) diff --git a/KubeOS-Rust/manager/src/sys_mgmt/config.rs b/KubeOS-Rust/manager/src/sys_mgmt/config.rs index 8e42fa18..a491a429 100644 --- a/KubeOS-Rust/manager/src/sys_mgmt/config.rs +++ b/KubeOS-Rust/manager/src/sys_mgmt/config.rs @@ -826,13 +826,10 @@ mod tests { let mut executor = MockCommandExec::new(); // the output shows that current root menuentry is A - let command_output1 = r#"vda 23622320128 -vda1 /boot/efi vfat 61865984 BOOT -vda2 / ext4 3145728000 ROOT-A -vda3 ext4 2621440000 ROOT-B -vda4 /persist ext4 17791188992 PERSIST -"#; - executor.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output1.to_string())); + let findmnt_output1 = "/dev/vda2"; + let lsblk_output1 = "ext4 3145728000\n"; + executor.expect_run_command_with_output().times(1).returning(|_, _| Ok(findmnt_output1.to_string())); + executor.expect_run_command_with_output().times(1).returning(|_, _| Ok(lsblk_output1.to_string())); let result = grub_cmdline.get_config_partition(executor).unwrap(); // it should return false because the current root menuentry is A and we want to configure current partition @@ -840,14 +837,8 @@ vda4 /persist ext4 17791188992 PERSIST let mut executor = MockCommandExec::new(); - // the output shows that current root menuentry is A - let command_output1 = r#"vda 23622320128 -vda1 /boot/efi vfat 61865984 BOOT -vda2 / ext4 3145728000 ROOT-A -vda3 ext4 2621440000 ROOT-B -vda4 /persist ext4 17791188992 PERSIST -"#; - executor.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output1.to_string())); + executor.expect_run_command_with_output().times(1).returning(|_, _| Ok(findmnt_output1.to_string())); + executor.expect_run_command_with_output().times(1).returning(|_, _| Ok(lsblk_output1.to_string())); grub_cmdline.is_cur_partition = false; let result = grub_cmdline.get_config_partition(executor).unwrap(); // it should return true because the current root menuentry is A and we want to configure next partition diff --git a/KubeOS-Rust/manager/src/utils/partition.rs b/KubeOS-Rust/manager/src/utils/partition.rs index 4941ee9d..b2c095c6 100644 --- a/KubeOS-Rust/manager/src/utils/partition.rs +++ b/KubeOS-Rust/manager/src/utils/partition.rs @@ -25,43 +25,33 @@ pub struct PartitionInfo { /// get_partition_info returns the current partition info and the next partition info. pub fn get_partition_info(executor: &T) -> Result<(PartitionInfo, PartitionInfo), anyhow::Error> { - let lsblk = executor.run_command_with_output("lsblk", &["-blno", "NAME,MOUNTPOINT,FSTYPE,SIZE,LABEL"])?; let mut cur_partition = PartitionInfo::default(); let mut next_partition = PartitionInfo::default(); - let mut found_boot = 0; - trace!("get_partition_info lsblk command output:\n{}", lsblk); - for line in lsblk.lines() { - let res: Vec<&str> = line.split_whitespace().collect(); - if res.len() == 5 && res[4] == "BOOT" { - trace!("Found boot partition:\n{:?}", res); - found_boot = 2; - continue; - } - if found_boot > 0 { - trace!("Handling two root partitions:\n{:?}", res); - if res[1] == "/" { - // current partition - cur_partition.device = format!("/dev/{}", res[0]).to_string(); - cur_partition.fs_type = res[2].to_string(); - cur_partition.size = res[3] - .parse() - .with_context(|| format!("Failed to parse current partition size to i64: \"{}\"", res[3]))?; - cur_partition.menuentry = if res[0].contains("2") { String::from("A") } else { String::from("B") }; - } else { - // next partition - next_partition.device = format!("/dev/{}", res[0]).to_string(); - next_partition.fs_type = res[1].to_string(); - next_partition.size = res[2] - .parse() - .with_context(|| format!("Failed to parse next partition size to i64: \"{}\"", res[2]))?; - next_partition.menuentry = if res[0].contains("2") { String::from("A") } else { String::from("B") }; - } - found_boot -= 1; - } + cur_partition.device = executor.run_command_with_output("findmnt", &["-no", "SOURCE", "--mountpoint", "/"])?; + trace!("{} is mounted on /", cur_partition.device); + if cur_partition.device.contains('2') { + cur_partition.menuentry = String::from("A"); + next_partition.menuentry = String::from("B"); + next_partition.device = cur_partition.device.replace("2", "3"); + } else if cur_partition.device.contains('3') { + cur_partition.menuentry = String::from("B"); + next_partition.menuentry = String::from("A"); + next_partition.device = cur_partition.device.replace("3", "2"); + } else { + bail!("Failed to get partition info, / is not mounted on the second or the third partition"); } - if cur_partition.menuentry.is_empty() || next_partition.menuentry.is_empty() { - bail!("Failed to get partition info, lsblk output: {}", lsblk); + let lsblk = executor.run_command_with_output("lsblk", &["-blno", "FSTYPE,SIZE", &cur_partition.device])?; + trace!("get_partition_info lsblk command output:\n{}", lsblk); + let elements: Vec<&str> = lsblk.split_whitespace().collect(); + if elements.len() != 2 { + bail!("Failed to get partition info of FSTYPE and SIZE, lsblk output: {}", lsblk); } + cur_partition.fs_type = elements[0].to_string(); + next_partition.fs_type = elements[0].to_string(); + cur_partition.size = elements[1] + .parse() + .with_context(|| format!("Failed to parse current partition size to i64: \"{}\"", elements[1]))?; + next_partition.size = cur_partition.size; Ok((cur_partition, next_partition)) } @@ -94,14 +84,11 @@ mod tests { #[test] fn test_get_partition_info() { init(); - let command_output1 = r#"vda 23622320128 -vda1 /boot/efi vfat 61865984 BOOT -vda2 / ext4 3145728000 ROOT-A -vda3 ext4 2621440000 ROOT-B -vda4 /persist ext4 17791188992 PERSIST -"#; + let findmnt_output1 = "/dev/vda2"; + let lsblk_output1 = "ext4 3145728000\n"; let mut mock = MockCommandExec::new(); - mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output1.to_string())); + mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(findmnt_output1.to_string())); + mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(lsblk_output1.to_string())); let res = get_partition_info(&mock).unwrap(); let expect_res = ( PartitionInfo { @@ -114,25 +101,22 @@ vda4 /persist ext4 17791188992 PERSIST device: "/dev/vda3".to_string(), menuentry: "B".to_string(), fs_type: "ext4".to_string(), - size: 2621440000, + size: 3145728000, }, ); assert_eq!(res, expect_res); - let command_output2 = r#"vda 23622320128 -vda1 /boot/efi vfat 61865984 BOOT -vda2 ext4 3145728000 ROOT-A -vda3 / ext4 2621440000 ROOT-B -vda4 /persist ext4 17791188992 PERSIST -"#; - mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output2.to_string())); + let findmnt_output2 = "/dev/vda3"; + let lsblk_output2 = "ext4 3145728000\n"; + mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(findmnt_output2.to_string())); + mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(lsblk_output2.to_string())); let res = get_partition_info(&mock).unwrap(); let expect_res = ( PartitionInfo { device: "/dev/vda3".to_string(), menuentry: "B".to_string(), fs_type: "ext4".to_string(), - size: 2621440000, + size: 3145728000, }, PartitionInfo { device: "/dev/vda2".to_string(), @@ -148,8 +132,8 @@ vda4 /persist ext4 17791188992 PERSIST let res = get_partition_info(&mock); assert!(res.is_err()); - let command_output4 = "sda4 / ext4 13000245248"; - mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output4.to_string())); + let findmnt_output3 = "/dev/vda4"; + mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(findmnt_output3.to_string())); let res = get_partition_info(&mock); assert!(res.is_err()); } -- 2.39.5 (Apple Git-154)