Skip to content

Commit f09ce77

Browse files
committed
this will probably work, but is rancid
if phd-runner decides to run with parallelism > 1, the tmpdir and artifact directories, which phd-runner will write to from each framework, are rewritten to be unique per-framework. this means the directory layout changes based on available parallelism, and makes the `phd-run-with-args.sh` script somewhat more gross, and generally is pretty unfortunate. at this point it's just to demonstrate that something is possible, but this really deserves the requisite surgery to share one log dir and one artifact dir across the Frameworks.
1 parent e0d4da0 commit f09ce77

File tree

5 files changed

+90
-11
lines changed

5 files changed

+90
-11
lines changed

.github/buildomat/phd-run-with-args.sh

+13-1
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,20 @@ set +e
6464
failcount=$?
6565
set -e
6666

67+
# Disable errexit again because we may try collecting logs from runners that ran
68+
# no tests (in which case *.log doesn't expand and tar will fail to find a file
69+
# by that literal name)
70+
set +e
6771
tar -czvf /tmp/phd-tmp-files.tar.gz \
68-
-C /tmp/propolis-phd /tmp/propolis-phd/*.log
72+
-C $tmpdir $tmpdir/*.log
73+
for runnerdir in $tmpdir/runner-*; do
74+
if [ -d "$runnerdir" ]; then
75+
tar -rzvf /tmp/phd-tmp-files.tar.gz \
76+
-C $runnerdir $runnerdir/*.log
77+
fi
78+
done
79+
set -e
80+
6981

7082
exitcode=0
7183
if [ $failcount -eq 0 ]; then

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cpuid-utils/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ bhyve_api.workspace = true
1010
propolis_api_types = {workspace = true, optional = true}
1111
propolis_types.workspace = true
1212
thiserror.workspace = true
13+
uuid.workspace = true
1314

1415
[dev-dependencies]
1516
proptest.workspace = true

crates/cpuid-utils/src/host.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use bhyve_api::{VmmCtlFd, VmmFd};
66
use propolis_types::{CpuidIdent, CpuidValues, CpuidVendor};
77
use thiserror::Error;
8+
use uuid::Uuid;
89

910
use crate::{
1011
bits::{
@@ -32,7 +33,11 @@ struct Vm(bhyve_api::VmmFd);
3233

3334
impl Vm {
3435
fn new() -> Result<Self, GetHostCpuidError> {
35-
let name = format!("cpuid-gen-{}", std::process::id());
36+
let name = format!(
37+
"cpuid-gen-{}-{}",
38+
std::process::id(),
39+
Uuid::new_v4()
40+
);
3641
let mut req = bhyve_api::vm_create_req::new(name.as_bytes())
3742
.expect("valid VM name");
3843

phd-tests/runner/src/main.rs

+69-9
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,9 @@ async fn run_tests(run_opts: &RunOptions) -> anyhow::Result<ExecutionStats> {
175175

176176
let mut runners = Vec::new();
177177

178-
// Create up to parallelism collections of PHD framework settings. For the
179-
// most part we can reuse the same settings for all test-running tasks -
180-
// state is not mutably shared. The important exception is port ranges for
181-
// servers PHD will run, where we want non-overlapping port ranges to ensure
182-
// that concurrent tests don't accidentally use a neighbor's servers.
183-
for i in 0..parallelism {
184-
let port_range = (9000 + PORT_RANGE_PER_RUNNER * i)
185-
..(9000 + PORT_RANGE_PER_RUNNER * (i + 1));
178+
if parallelism == 1 {
179+
// If there's only one test runner, the provided config is by definition
180+
// not going to have issues with parallelism. Consume it directly.
186181
let ctx_params = FrameworkParameters {
187182
propolis_server_path: run_opts.propolis_server_cmd.clone(),
188183
crucible_downstairs: run_opts.crucible_downstairs()?,
@@ -195,7 +190,7 @@ async fn run_tests(run_opts: &RunOptions) -> anyhow::Result<ExecutionStats> {
195190
default_guest_memory_mib: run_opts.default_guest_memory_mib,
196191
default_guest_os_artifact: run_opts.default_guest_artifact.clone(),
197192
default_bootrom_artifact: run_opts.default_bootrom_artifact.clone(),
198-
port_range,
193+
port_range: 9000..(9000 + PORT_RANGE_PER_RUNNER),
199194
max_buildomat_wait: Duration::from_secs(
200195
run_opts.max_buildomat_wait_secs,
201196
),
@@ -209,6 +204,71 @@ async fn run_tests(run_opts: &RunOptions) -> anyhow::Result<ExecutionStats> {
209204

210205
let fixtures = TestFixtures::new(ctx.clone()).unwrap();
211206
runners.push((ctx, fixtures));
207+
} else {
208+
// Create up to parallelism collections of PHD framework settings. Many
209+
// settings can be reused directly, but some describe state the
210+
// framework will mutate (causing ports to be allocated, fetching
211+
// artifacts, etc). Take the provided config and make it safe for
212+
// Frameworks to use independently.
213+
//
214+
// This implies downloading artifacts {parallelism} times, extracting
215+
// artifacts redundantly for the different artifact directories, makes
216+
// terrible use of the port range. It'd be much better to accept some
217+
// owner of the shared state that each Framework can take as a
218+
// parameter.
219+
220+
// We'll separate directories by which Framework they're for in some
221+
// cases, below. Those uniquifying names will be padded to all be the
222+
// length of the longest uniquifier to help make it kind of legible..
223+
let pad_size = format!("{}", parallelism - 1).len();
224+
225+
for i in 0..parallelism {
226+
let port_range = (9000 + PORT_RANGE_PER_RUNNER * i)
227+
..(9000 + PORT_RANGE_PER_RUNNER * (i + 1));
228+
let mut unshared_tmp_dir = run_opts.tmp_directory.clone();
229+
unshared_tmp_dir.push(format!("runner-{:pad_size$}", i));
230+
231+
let mut unshared_artifacts_dir =
232+
run_opts.artifact_directory().clone();
233+
unshared_artifacts_dir.push(format!("runner-{:pad_size$}", i));
234+
235+
// The runner directories may well not exist, we just invented them
236+
// after all. Create them so phd-runner can use them. This is awful.
237+
// Sorry.
238+
let _ = std::fs::create_dir(&unshared_tmp_dir);
239+
let _ = std::fs::create_dir(&unshared_artifacts_dir);
240+
241+
let ctx_params = FrameworkParameters {
242+
propolis_server_path: run_opts.propolis_server_cmd.clone(),
243+
crucible_downstairs: run_opts.crucible_downstairs()?,
244+
base_propolis: run_opts.base_propolis(),
245+
tmp_directory: unshared_tmp_dir,
246+
artifact_directory: unshared_artifacts_dir,
247+
artifact_toml: run_opts.artifact_toml_path.clone(),
248+
server_log_mode: run_opts.server_logging_mode,
249+
default_guest_cpus: run_opts.default_guest_cpus,
250+
default_guest_memory_mib: run_opts.default_guest_memory_mib,
251+
default_guest_os_artifact: run_opts
252+
.default_guest_artifact
253+
.clone(),
254+
default_bootrom_artifact: run_opts
255+
.default_bootrom_artifact
256+
.clone(),
257+
port_range,
258+
max_buildomat_wait: Duration::from_secs(
259+
run_opts.max_buildomat_wait_secs,
260+
),
261+
};
262+
263+
let ctx = Arc::new(
264+
Framework::new(ctx_params)
265+
.await
266+
.expect("should be able to set up a test context"),
267+
);
268+
269+
let fixtures = TestFixtures::new(ctx.clone()).unwrap();
270+
runners.push((ctx, fixtures));
271+
}
212272
}
213273

214274
// Run the tests and print results.

0 commit comments

Comments
 (0)