-
Notifications
You must be signed in to change notification settings - Fork 31
phd: check exit status of commands #1054
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,27 +24,28 @@ use uuid::Uuid; | |
| /// startup and shutdown with Hyper-V emulation enabled. | ||
| async fn guest_detect_hyperv(vm: &TestVm) -> anyhow::Result<()> { | ||
| if vm.guest_os_kind().is_linux() { | ||
| // Many Linux distros come with systemd installed out of the box. On | ||
| // these distros, it's easiest to use `systemd-detect-virt` to determine | ||
| // whether the guest thinks it's running on a Hyper-V-compatible | ||
| // hypervisor. (Whether any actual enlightenments are enabled is another | ||
| // story, but those can often be detected by other means.) | ||
| let out = vm.run_shell_command("systemd-detect-virt").await?; | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. with this change, the shell command completes with status, so this change ends up being a motivator to detect the hypervisor in a more robust way. yay! |
||
| if out.contains("systemd-detect-virt: not found") { | ||
| warn!( | ||
| "guest doesn't support systemd-detect-virt, can't verify it \ | ||
| detected Hyper-V support" | ||
| ); | ||
| } else { | ||
| assert_eq!(out, "microsoft"); | ||
| } | ||
| // One might imagine we could simply use `systemd-detect-virt` to check | ||
| // hypervisor information here, but it's not present out of the box on | ||
| // Alpine. In the interest of exercising Hyper-V in typical CI runs on a | ||
| // standard Alpine image, detect Hyper-V in a... worse but reliable way: | ||
| // looking for relevant logs in dmesg. This should work for all Linuxes | ||
| // from later than May-ish 2010 (>2.6.34 or so). If we don't see Hyper-V | ||
| // reported in dmesg either it's genuinely not detected, it's a very old | ||
| // Linux, or it's a new Linux and dmesg text has changed. | ||
|
Comment on lines
+33
to
+34
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i suppose it could possibly also have fallen off the end of the dmesg ringbuffer if something is spewing out a ton of errors perhaps?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh god. file that under "conditions i never want to think about". but yes. |
||
| const HV_TEXT: &str = "Hypervisor detected: Microsoft Hyper-V"; | ||
|
|
||
| // No "sudo" here because Alpine doesn't have sudo; for Linux tests we | ||
| // expect to run test commands as root anyway. | ||
| vm.run_shell_command(&format!("dmesg | grep \"{HV_TEXT}\"")).await?; | ||
| } else if vm.guest_os_kind().is_windows() { | ||
| // Windows is good about giving signals that it's running in a Hyper-V | ||
| // *root partition*, but offers no clear signal as to whether it has | ||
| // detected a Hyper-V host when it's running as a non-root guest. (There | ||
| // are methods for detecting whether Windows is running as a guest, but | ||
| // these don't identify the detected hypervisor type.) | ||
| warn!("running on Windows, can't verify it detected Hyper-V support"); | ||
| } else { | ||
| warn!("unknown guest type, can't verify it detected Hyper-V support"); | ||
| } | ||
|
|
||
| Ok(()) | ||
|
|
@@ -56,6 +57,16 @@ async fn hyperv_smoke_test(ctx: &TestCtx) { | |
| cfg.guest_hv_interface(GuestHypervisorInterface::HyperV { | ||
| features: Default::default(), | ||
| }); | ||
| // For reasons absolutely indecipherable to me, Alpine (3.16, kernel | ||
| // 5.15.41-0-virt) seems to lose some early dmesg lines if booted with less | ||
| // than four vCPUs. Among the early dmesg lines are `Hypervisor detected: | ||
| // Microsoft Hyper-V` that we look for as confirmation that Linux knows | ||
| // there's a Hyper-V-like hypervisor present. | ||
|
Comment on lines
+60
to
+64
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| // | ||
| // I'd love to debug exactly why this is relevant to the contents of dmesg | ||
| // (the remaining log is identical and it doesn't seem that the ring buffer | ||
| // is full), but I really can't justify the time! | ||
| cfg.cpus(4); | ||
| let mut vm = ctx.spawn_vm(&cfg, None).await?; | ||
| vm.launch().await?; | ||
| vm.wait_to_boot().await?; | ||
|
|
@@ -69,6 +80,9 @@ async fn hyperv_lifecycle_test(ctx: &TestCtx) { | |
| cfg.guest_hv_interface(GuestHypervisorInterface::HyperV { | ||
| features: Default::default(), | ||
| }); | ||
| // Spooky load-bearing vCPU count to preserve dmesg log lines. See the | ||
| // comment in `hyperv_smoke_test`. | ||
| cfg.cpus(4); | ||
| let mut vm = ctx.spawn_vm(&cfg, None).await?; | ||
| vm.launch().await?; | ||
| vm.wait_to_boot().await?; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,7 +55,11 @@ mod from_base { | |
| spawn_base_vm(ctx, "migration_from_base_and_back").await?; | ||
| source.launch().await?; | ||
| source.wait_to_boot().await?; | ||
| let lsout = source.run_shell_command("ls foo.bar 2> /dev/null").await?; | ||
| // `ls` with no results exits non-zero, so expect an error here. | ||
| let lsout = source | ||
| .run_shell_command("ls foo.bar 2> /dev/null") | ||
| .check_err() | ||
| .await?; | ||
| assert_eq!(lsout, ""); | ||
|
|
||
| // create an empty file on the source VM. | ||
|
|
@@ -74,8 +78,9 @@ mod from_base { | |
| // the file should still exist on the target VM after migration. | ||
| let lsout = target | ||
| .run_shell_command("ls foo.bar") | ||
| .ignore_status() | ||
| .await | ||
| .expect("`ls foo.bar` should succeed"); | ||
| .expect("can try to run `ls foo.bar`"); | ||
| assert_eq!(lsout, "foo.bar"); | ||
| }) | ||
| }, | ||
|
|
@@ -275,7 +280,9 @@ mod running_process { | |
| )) | ||
| .await?; | ||
| vm.run_shell_command("chmod +x dirt.sh").await?; | ||
| let run_dirt = vm.run_shell_command("./dirt.sh").await?; | ||
| // When dirt.sh suspends itself, the parent shell will report a non-zero | ||
| // status (one example is 148: 128 + SIGTSTP aka 20 on Linux). | ||
| let run_dirt = vm.run_shell_command("./dirt.sh").check_err().await?; | ||
| assert!(run_dirt.contains("made dirt"), "dirt.sh failed: {run_dirt:?}"); | ||
| assert!( | ||
| run_dirt.contains("Stopped"), | ||
|
|
@@ -314,7 +321,8 @@ async fn multiple_migrations(ctx: &TestCtx) { | |
| async fn run_smoke_test(ctx: &TestCtx, mut source: TestVm) -> Result<()> { | ||
| source.launch().await?; | ||
| source.wait_to_boot().await?; | ||
| let lsout = source.run_shell_command("ls foo.bar 2> /dev/null").await?; | ||
| let lsout = | ||
| source.run_shell_command("ls foo.bar 2> /dev/null").check_err().await?; | ||
| assert_eq!(lsout, ""); | ||
|
|
||
| // create an empty file on the source VM. | ||
|
|
@@ -329,8 +337,9 @@ async fn run_smoke_test(ctx: &TestCtx, mut source: TestVm) -> Result<()> { | |
| // the file should still exist on the target VM after migration. | ||
| let lsout = target | ||
| .run_shell_command("ls foo.bar") | ||
| .ignore_status() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since we're asserting on the output of this isn't super important but iirc i'd broken the test in a really confusing way where this helped explain what was happening, rather than just saying the right thing wasn't happening. |
||
| .await | ||
| .expect("`ls foo.bar` should succeed after migration"); | ||
| .expect("can try to run `ls foo.bar`"); | ||
| assert_eq!(lsout, "foo.bar"); | ||
| }) | ||
| }, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, it occurs to me that this could maybe be jammed together into a method on
self.vm, not that we are currently calling it anywhere else...