From 1a6c979234fb670c9d5f82e29413a4b401ad430d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo?= Date: Tue, 29 Oct 2024 14:52:40 +0100 Subject: [PATCH 1/5] resctl-bench: upload: handle errors when opening the results file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the code for opening and processing the results file and handle and provide a more informative error message. Signed-off-by: Ricardo Cañuelo --- resctl-bench/src/main.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/resctl-bench/src/main.rs b/resctl-bench/src/main.rs index c283616..8853b87 100644 --- a/resctl-bench/src/main.rs +++ b/resctl-bench/src/main.rs @@ -255,17 +255,10 @@ impl Program { fn do_upload(&mut self) -> Result<()> { let args = &self.args_file.data; - let path = Path::new(&args.result) - .file_name() - .unwrap() - .to_string_lossy() - .to_string(); - - let mut data = Vec::::new(); - let mut f = std::fs::OpenOptions::new().read(true).open(&path)?; - f.read_to_end(&mut data)?; + let mut data: Vec = std::fs::read(&args.result) + .context(format!("Error opening or reading {}", &args.result))?; - if !path.ends_with(".gz") { + if !args.result.ends_with(".gz") { let deflated = std::mem::take(&mut data); let mut encoder = libflate::gzip::Encoder::new(&mut data)?; encoder.write_all(&deflated).context("Compressing file")?; From 29435bdca66d37740834dea0c74dcb0dbb257014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo?= Date: Tue, 29 Oct 2024 14:53:41 +0100 Subject: [PATCH 2/5] resctl-bench: catch and print server error responses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catch the scenario where the server returns something that isn't a well formed json object. Signed-off-by: Ricardo Cañuelo --- resctl-bench/src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resctl-bench/src/main.rs b/resctl-bench/src/main.rs index 8853b87..4ae0edc 100644 --- a/resctl-bench/src/main.rs +++ b/resctl-bench/src/main.rs @@ -278,7 +278,13 @@ impl Program { .with_json(&request)? .send()?; - let response: LambdaResponse = serde_json::from_str(response.as_str()?)?; + let Ok(response) = serde_json::from_str::(response.as_str()?) else { + error!( + "Failed to submit benchmark. Server response: {}", + response.as_str()? + ); + std::process::exit(1); + }; if response.issue.is_none() { if let Some(error_message) = response.error_message { error!("Failed to submit benchmark: {}", error_message); From 0169fe066472b2c1b0a4a2b7257223e1d4cdea17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo?= Date: Tue, 29 Oct 2024 14:55:53 +0100 Subject: [PATCH 3/5] resctl-bench: lambda: sanity checks for input request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the request contents provided by `resctl-bench upload` and return the error messages to the client as error responses. Signed-off-by: Ricardo Cañuelo --- resctl-bench/src/lambda.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/resctl-bench/src/lambda.rs b/resctl-bench/src/lambda.rs index 4fbc890..a70d7b7 100644 --- a/resctl-bench/src/lambda.rs +++ b/resctl-bench/src/lambda.rs @@ -48,8 +48,25 @@ pub fn init_lambda() { pub async fn run() -> Result<()> { let handler = |event: LambdaEvent| async move { let helper = LambdaHelper::new().await; - let request: Request = serde_json::from_str(event.payload.body.as_ref().unwrap().as_str())?; - + let Some(event_body) = event.payload.body else { + error!("No body found in event payload: {:?}", event.payload); + return Ok(Response { + issue: None, + error_type: Some(format!("Custom")), + error_message: Some(format!("No body found in event payload.")), + }); + }; + let request: Request = match serde_json::from_str(event_body.as_str()) { + Ok(req) => req, + Err(e) => { + error!("Error parsing event body: {}", e); + return Ok(Response { + issue: None, + error_type: Some(format!("Custom")), + error_message: Some(format!("Error parsing event body: {}", e)), + }); + } + }; // Unpack the base64 encoded gz-compressed file. This is safe because Lambda has a hard // limit on the size of the requests (6MB at the moment). let data = base64::decode(&request.data)?; From 0a793d86e16c3ff85dc4f5563e4b026f42264546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo?= Date: Tue, 29 Oct 2024 14:58:27 +0100 Subject: [PATCH 4/5] resctl-bench: lambda: add error log if file was already submitted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an error log line to improve debugging and traceability in the AWS lambda logs. Signed-off-by: Ricardo Cañuelo --- resctl-bench/src/lambda.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/resctl-bench/src/lambda.rs b/resctl-bench/src/lambda.rs index a70d7b7..8e7dbc3 100644 --- a/resctl-bench/src/lambda.rs +++ b/resctl-bench/src/lambda.rs @@ -82,6 +82,7 @@ pub async fn run() -> Result<()> { let object_name = helper.object_name_from_hash(&data)?; if helper.s3_object_exists(&object_name).await? { + error!("File {} has already been submitted", object_name); return Ok(Response { issue: None, error_type: Some(format!("Custom")), From a861c55aab8c6e0249c11305fc7a4a0b312ef5ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo?= Date: Tue, 29 Oct 2024 15:00:54 +0100 Subject: [PATCH 5/5] resctl-bench: lambda: return Github-related errors as responses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide error messages both for lambda logs and for the client instead of panicking and showing a stack trace. Signed-off-by: Ricardo Cañuelo --- resctl-bench/src/lambda.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/resctl-bench/src/lambda.rs b/resctl-bench/src/lambda.rs index 8e7dbc3..80e7e45 100644 --- a/resctl-bench/src/lambda.rs +++ b/resctl-bench/src/lambda.rs @@ -99,10 +99,18 @@ pub async fn run() -> Result<()> { &sysinfo, &format!("{}\n\n{}```\n{}\n```", s3_url, identification, summary), ) - .await?; + .await; + if let Err(e) = issue_url { + error!("Error creating Github issue: {:#}", e); + return Ok(Response { + issue: None, + error_type: Some(format!("Custom")), + error_message: Some(format!("Error creating Github issue: {}", e)), + }); + } Ok::<_, Error>(Response { - issue: Some(issue_url), + issue: Some(issue_url.unwrap()), error_type: None, error_message: None, }) @@ -176,11 +184,11 @@ impl LambdaHelper { .set_name(Some("/iocost-bot/appid".to_string())) .send() .await - .expect("Failed to query parameter") + .context("Failed to query AWS parameter /iocost-bot/appid")? .parameter - .expect("Could not find parameter") + .context("Could not find AWS parameter /iocost-bot/appid")? .value - .expect("Parameter value is None"); + .context("Value of parameter AWS /iocost-bot/appid is None")?; let pem = self .ssm @@ -188,15 +196,16 @@ impl LambdaHelper { .set_name(Some("/iocost-bot/privatekey".to_string())) .send() .await - .expect("Failed to query parameter") + .context("Failed to query parameter AWS /iocost-bot/privatekey")? .parameter - .expect("Could not find parameter") + .context("Could not find parameter AWS /iocost-bot/privatekey")? .value - .expect("Parameter value is None"); + .context("Value of parameter AWS /iocost-bot/privatekey is None")?; let token = octocrab::auth::create_jwt( app_id.parse::().unwrap().into(), - &jsonwebtoken::EncodingKey::from_rsa_pem(pem.as_bytes()).unwrap(), + &jsonwebtoken::EncodingKey::from_rsa_pem(pem.as_bytes()) + .context("Couldn't create a JWT for Github authentication")?, ) .unwrap();