netbench-orchestrator/src/orchestrator/report.rs (133 lines of code) (raw):

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 use crate::{ec2_utils::InfraDetail, orchestrator::OrchestratorConfig, s3_utils, OrchResult}; use aws_sdk_s3::primitives::{ByteStream, SdkBody}; use std::{path::Path, process::Command}; use tracing::{debug, info, trace}; pub async fn generate_report( s3_client: &aws_sdk_s3::Client, unique_id: &str, infra: &InfraDetail, config: &OrchestratorConfig, ) -> OrchResult<()> { let tmp_dir = tempfile::Builder::new() .prefix(unique_id) .tempdir() .expect("failed to create temp dir") .into_path(); let tmp_dir = tmp_dir.to_str().expect("failed to create temp dir"); download_results(unique_id, config, tmp_dir).await?; generate_report_from_results(tmp_dir).await?; upload_report_to_s3(unique_id, config, tmp_dir).await?; update_report_url(s3_client, unique_id, config).await?; println!("Report Finished!: Successful: true"); println!("URL: {}/report/index.html", config.cf_url(unique_id)); info!("Report Finished!: Successful: true"); info!("URL: {}/report/index.html", config.cf_url(unique_id)); download_remote_logs(unique_id, infra); Ok(()) } async fn upload_report_to_s3( unique_id: &str, config: &OrchestratorConfig, tmp_dir: &str, ) -> OrchResult<()> { let mut cmd = Command::new("aws"); let output = cmd .args([ "s3", "sync", tmp_dir, &format!( "s3://{}/{}", config.cdk_config.netbench_runner_public_s3_bucket(), unique_id ), ]) .output() .unwrap(); debug!("{:?}", cmd); trace!("{:?}", output); assert!(cmd.status().expect("aws sync").success(), "aws sync"); Ok(()) } async fn generate_report_from_results(tmp_dir: &str) -> OrchResult<()> { let results_path = format!("{}/results", tmp_dir); let report_path = format!("{}/report", tmp_dir); let mut cmd = Command::new("s2n-netbench"); cmd.args(["report-tree", &results_path, &report_path]); debug!("{:?}", cmd); let status = cmd.status().expect("s2n-netbench command failed"); assert!(status.success(), " s2n-netbench command failed"); Ok(()) } async fn download_results( unique_id: &str, config: &OrchestratorConfig, tmp_dir: &str, ) -> OrchResult<()> { let mut cmd = Command::new("aws"); let output = cmd .args([ "s3", "sync", &format!( "s3://{}/{}", config.cdk_config.netbench_runner_public_s3_bucket(), unique_id ), tmp_dir, ]) .output() .unwrap(); debug!("{:?}", cmd); trace!("{:?}", output); assert!(cmd.status().expect("aws sync").success(), "aws sync"); Ok(()) } async fn update_report_url( s3_client: &aws_sdk_s3::Client, unique_id: &str, config: &OrchestratorConfig, ) -> OrchResult<()> { let body = ByteStream::new(SdkBody::from(format!( "<a href=\"{}/report/index.html\">Final Report</a>", config.cf_url(unique_id) ))); let key = format!("{}/finished-step-0", unique_id); s3_utils::upload_object( s3_client, config.cdk_config.netbench_runner_public_s3_bucket(), body, &key, ) .await?; Ok(()) } // This function is best effort and will not return an error. // // Requires ssh access to the host. See STATE.ssh_key_name for more info fn download_remote_logs(unique_id: &str, infra: &InfraDetail) { // get logs let get_logs = true; if get_logs { infra.public_client_ips().iter().for_each(|ip| { let log_folder = format!("./target/logs/{unique_id}/client_{ip}"); std::fs::create_dir_all(Path::new(&log_folder)).expect("create log dir"); let res = Command::new("scp") .args([ "-oStrictHostKeyChecking=no", &format!("ec2-user@{ip}:netbench_orchestrator/target/russula*"), &log_folder, ]) .output(); debug!("client log download succeeded: {:?}", res.ok()); }); infra.public_server_ips().iter().for_each(|ip| { let log_folder = format!("./target/logs/{unique_id}/server_{ip}"); std::fs::create_dir_all(Path::new(&log_folder)).expect("create log dir"); let res = Command::new("scp") .args([ "-oStrictHostKeyChecking=no", &format!("ec2-user@{ip}:netbench_orchestrator/target/russula*"), &log_folder, ]) .output(); debug!("server log download succeeded: {:?}", res.ok()); }); } }