use cortex_client::apis::configuration::Configuration;
use std::env;
pub fn setup_configuration() -> Result<Configuration, String> {
let base_path = env::var("CORTEX_ENDPOINT")
.map_err(|_| "CORTEX_ENDPOINT environment variable not set. Please set it to your Cortex API URL (e.g., http://localhost:9000/api).".to_string())?;
let api_key = env::var("CORTEX_API_KEY").map_err(|_| {
"CORTEX_API_KEY environment variable not set. Please set your Cortex API key.".to_string()
})?;
let mut configuration = Configuration::new();
configuration.base_path = base_path;
configuration.bearer_access_token = Some(api_key);
Ok(configuration)
}
pub async fn get_analyzer_id_by_name(
config: &Configuration,
analyzer_name_to_find: &str,
) -> Result<Option<String>, Box<dyn std::error::Error>> {
println!(
"Fetching all analyzer instances to find ID for '{}'...",
analyzer_name_to_find
);
let find_request = Some(cortex_client::models::AnalyzerFindRequest::default());
match cortex_client::apis::analyzer_api::find_analyzers(config, find_request).await {
Ok(analyzer_instances) => {
for analyzer_instance in analyzer_instances {
if let Some(name) = &analyzer_instance.name {
if name == analyzer_name_to_find {
if let Some(id) = analyzer_instance._id {
println!(
"Found analyzer ID '{}' for name '{}'",
id, analyzer_name_to_find
);
return Ok(Some(id));
}
}
}
}
println!("Analyzer with name '{}' not found.", analyzer_name_to_find);
Ok(None)
}
Err(e) => {
eprintln!("Error fetching analyzer instances: {:?}", e);
Err(Box::new(e))
}
}
}
pub async fn run_job_and_wait_for_report(
config: &cortex_client::apis::configuration::Configuration,
analyzer_worker_id: &str,
job_request: cortex_client::models::JobCreateRequest,
analyzer_name_for_log: &str, observable_for_log: &str, ) -> Result<cortex_client::models::JobReportResponse, Box<dyn std::error::Error>> {
use cortex_client::apis::job_api;
use std::time::Duration;
println!(
"Submitting job to analyzer '{}' (ID: '{}') for observable: {}...",
analyzer_name_for_log, analyzer_worker_id, observable_for_log
);
match job_api::create_analyzer_job(config, analyzer_worker_id, job_request).await {
Ok(job_response) => {
println!(
"Successfully created job. Job ID: {}, Status: {:?}",
job_response._id.as_ref().unwrap_or(&"unknown".to_string()),
job_response.status
);
if let Some(job_id) = job_response._id {
println!(
"\nAttempting to fetch report for job ID: {} with retries...",
job_id
);
let max_retries = 3;
let retry_delay = Duration::from_secs(15);
for attempt in 1..=max_retries {
println!(
"\nAttempt {} of {} to check job status...",
attempt, max_retries
);
match job_api::get_job_by_id(config, &job_id).await {
Ok(job_details) => {
println!("Current job status: {:?}", job_details.status);
match job_details.status {
Some(cortex_client::models::job::Status::Success) => {
println!(
"Job status is Success. Attempting to fetch report..."
);
match job_api::get_job_report(config, &job_id).await {
Ok(report_response) => {
println!("\n✅ Successfully fetched job report!");
return Ok(report_response);
}
Err(e) => {
let err_msg = format!("Error fetching job report even though status was Success: {:?}", e);
eprintln!("{}", err_msg);
return Err(err_msg.into());
}
}
}
Some(cortex_client::models::job::Status::Failure) => {
let err_msg = format!(
"Job failed. Error message: {:?}",
job_details.error_message.unwrap_or_else(|| Some(
"No error message provided.".to_string()
))
);
eprintln!("{}", err_msg);
return Err(err_msg.into());
}
Some(cortex_client::models::job::Status::InProgress)
| Some(cortex_client::models::job::Status::Waiting) => {
if attempt < max_retries {
println!("Job is still {:?}. Waiting for {} seconds before next attempt...", job_details.status.unwrap(), retry_delay.as_secs());
tokio::time::sleep(retry_delay).await;
} else {
let info_msg = format!("Job did not complete (still {:?}) after {} attempts. Job ID: {}", job_details.status.unwrap(), max_retries, job_id);
println!("{}", info_msg);
return Err(info_msg.into());
}
}
Some(cortex_client::models::job::Status::Deleted) => {
let err_msg = format!(
"Job has been deleted. Cannot fetch report. Job ID: {}",
job_id
);
eprintln!("{}", err_msg);
return Err(err_msg.into());
}
None => {
let warn_msg = format!("Job status is unknown. Cannot determine if report is ready. Job ID: {}", job_id);
eprintln!("{}", warn_msg);
if attempt < max_retries {
tokio::time::sleep(retry_delay).await;
} else {
let info_msg = format!("Job status remained unknown after {} attempts. Job ID: {}", max_retries, job_id);
println!("{}", info_msg);
return Err(info_msg.into());
}
}
}
}
Err(e) => {
eprintln!(
"\nError fetching job details on attempt {}: {:?}",
attempt, e
);
if attempt == max_retries {
let err_msg = format!("Could not fetch job details after {} attempts for job ID: {}. Error: {:?}", max_retries, job_id, e);
eprintln!("{}", err_msg);
return Err(err_msg.into());
} else {
tokio::time::sleep(retry_delay).await;
}
}
}
}
let final_err_msg = format!(
"\nCould not retrieve job report for job ID {} after {} attempts.",
job_id, max_retries
);
eprintln!("{}", final_err_msg);
Err(final_err_msg.into())
} else {
let err_msg = "\nJob created, but no job ID was returned in the response. Cannot fetch report.".to_string();
eprintln!("{}", err_msg);
Err(err_msg.into())
}
}
Err(e) => {
let err_msg = format!(
"\nError creating analyzer job for '{}' on '{}': {:?}",
analyzer_name_for_log, observable_for_log, e
);
eprintln!("{}", err_msg);
Err(err_msg.into())
}
}
}