Skip to content

Commit c8f6937

Browse files
authoredFeb 7, 2024
PHD: convert to async (#633)
Convert the PHD framework to run on an async runtime. This makes it much easier to cancel running tests in response to signals. This, in turn, makes it easier to drop all of the objects created by a specific test case, which makes it much safer to add framework primitives that need to be cleaned up in an orderly fashion (e.g. ZFS-based copy-on-write file-backed guest disks). Tested via local runs with Alpine and Debian 11 guests.
1 parent 4902d82 commit c8f6937

28 files changed

+927
-703
lines changed
 

‎Cargo.lock

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

‎Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ num_enum = "0.5.11"
122122
owo-colors = "4"
123123
pin-project-lite = "0.2.13"
124124
proc-macro2 = "1.0"
125+
proc-macro-error = "1"
125126
progenitor = { git = "https://github.com/oxidecomputer/progenitor", ref = "v0.5.0" }
126127
quote = "1.0"
127128
rand = "0.8"

‎phd-tests/framework/src/artifacts/buildomat.rs

+24-23
Original file line numberDiff line numberDiff line change
@@ -35,48 +35,50 @@ impl Repo {
3535
Self(Cow::Borrowed(s))
3636
}
3737

38-
pub(super) fn artifact_for_commit(
38+
pub(super) async fn artifact_for_commit(
3939
self,
4040
series: Series,
4141
commit: Commit,
4242
filename: impl AsRef<Utf8Path>,
4343
downloader: &DownloadConfig,
4444
) -> anyhow::Result<BuildomatArtifact> {
4545
let filename = filename.as_ref();
46-
let sha256 = self.get_sha256(&series, &commit, filename, downloader)?;
46+
let sha256 =
47+
self.get_sha256(&series, &commit, filename, downloader).await?;
4748

4849
Ok(BuildomatArtifact { repo: self, series, commit, sha256 })
4950
}
5051

51-
pub(super) fn get_branch_head(
52+
pub(super) async fn get_branch_head(
5253
&self,
5354
branch: &str,
5455
) -> anyhow::Result<Commit> {
55-
(|| {
56+
async {
5657
let uri = format!("{BASE_URI}/branch/{self}/{branch}");
57-
let client = reqwest::blocking::ClientBuilder::new()
58+
let client = reqwest::ClientBuilder::new()
5859
.timeout(Duration::from_secs(5))
5960
.build()?;
6061
let req = client.get(uri).build()?;
61-
let rsp = client.execute(req)?;
62+
let rsp = client.execute(req).await?;
6263
let status = rsp.status();
6364
anyhow::ensure!(status.is_success(), "HTTP status: {status}");
64-
let bytes = rsp.bytes()?;
65+
let bytes = rsp.bytes().await?;
6566
str_from_bytes(&bytes)?.parse::<Commit>()
66-
})()
67+
}
68+
.await
6769
.with_context(|| {
6870
format!("Failed to determine HEAD commit for {self}@{branch}")
6971
})
7072
}
7173

72-
fn get_sha256(
74+
async fn get_sha256(
7375
&self,
7476
series: &Series,
7577
commit: &Commit,
7678
filename: &Utf8Path,
7779
downloader: &DownloadConfig,
7880
) -> anyhow::Result<String> {
79-
(|| {
81+
async {
8082
let filename = filename
8183
.file_name()
8284
.ok_or_else(|| {
@@ -105,9 +107,9 @@ impl Repo {
105107
)
106108
})?;
107109
let uri = format!("{BASE_URI}/file/{self}/{series}/{commit}/{filename}.sha256.txt");
108-
let bytes = downloader.download_buildomat_uri(&uri)?;
110+
let bytes = downloader.download_buildomat_uri(&uri).await?;
109111
str_from_bytes(&bytes).map(String::from)
110-
})().with_context(|| {
112+
}.await.with_context(|| {
111113
format!("Failed to get SHA256 for {self}@{commit}, series: {series}, file: {filename})")
112114
})
113115
}
@@ -206,7 +208,7 @@ impl super::DownloadConfig {
206208
/// retry duration. This retry logic serves as a mechanism for PHD to wait
207209
/// for an artifact we expect to exist to be published, when the build that
208210
/// publishes that artifact is still in progress.
209-
pub(super) fn download_buildomat_uri(
211+
pub(super) async fn download_buildomat_uri(
210212
&self,
211213
uri: &str,
212214
) -> anyhow::Result<bytes::Bytes> {
@@ -215,10 +217,9 @@ impl super::DownloadConfig {
215217
%uri,
216218
"Downloading file from Buildomat...",
217219
);
218-
let client = reqwest::blocking::ClientBuilder::new()
219-
.timeout(self.timeout)
220-
.build()?;
221-
let try_download = || {
220+
let client =
221+
reqwest::ClientBuilder::new().timeout(self.timeout).build()?;
222+
let try_download = || async {
222223
let request = client
223224
.get(uri)
224225
.build()
@@ -229,7 +230,9 @@ impl super::DownloadConfig {
229230

230231
let response = client
231232
.execute(request)
233+
.await
232234
.map_err(|e| backoff::Error::transient(e.into()))?;
235+
233236
if !response.status().is_success() {
234237
// when downloading a file from buildomat, we currently retry
235238
// all errors, since buildomat returns 500s when an artifact
@@ -252,17 +255,15 @@ impl super::DownloadConfig {
252255
);
253256
};
254257

255-
let bytes = backoff::retry_notify(
258+
let bytes = backoff::future::retry_notify(
256259
self.buildomat_backoff.clone(),
257260
try_download,
258261
log_retry,
259262
)
260-
.map_err(|e| match e {
261-
backoff::Error::Permanent(e) => e,
262-
backoff::Error::Transient { err, .. } => err,
263-
})
263+
.await
264264
.with_context(|| format!("Failed to download '{uri}' from Buildomat"))?
265-
.bytes()?;
265+
.bytes()
266+
.await?;
266267

267268
Ok(bytes)
268269
}

0 commit comments

Comments
 (0)
Please sign in to comment.