use async_trait::async_trait;
use instant::Instant;
use rand::Rng;
use rand::rng;
use rand::seq::IteratorRandom;
use rand_distr::Distribution;
use rand_distr::FisherF;
use yansi::Paint;
use crate::args::AppConfig;
use crate::data::TERRAFORM_AWS_RESOURCES_LIST;
use crate::data::TERRAFORM_AZURE_RESOURCES_LIST;
use crate::data::TERRAFORM_GCP_RESOURCES_LIST;
use crate::data::TERRAFORM_IDS_LIST;
use crate::io::{csleep, newline, print};
use crate::modules::Module;
pub struct Terraform;
async fn bold(msg: &str) {
print(format!("{}", Paint::new(msg).bold())).await;
newline().await;
}
#[async_trait(? Send)]
impl Module for Terraform {
fn name(&self) -> &'static str {
"terraform"
}
fn signature(&self) -> String {
"terraform --check".to_string()
}
async fn run(&self, appconfig: &AppConfig) {
let mut rng = rng();
let num_resources = rng.random_range(30..300);
print("Acquiring state lock. This may take a few moments...\r\n").await;
csleep(500).await;
let mut added = 0;
let mut changed = 0;
let mut destroyed = 0;
let start = Instant::now();
let cloud = match rng.random_range(0..3) {
0 => "AWS",
1 => "AZURE",
2 => "GCP",
_ => unreachable!(),
};
for _ in 1..num_resources {
let resource = match cloud {
"AWS" => TERRAFORM_AWS_RESOURCES_LIST
.iter()
.choose(&mut rng)
.unwrap(),
"AZURE" => TERRAFORM_AZURE_RESOURCES_LIST
.iter()
.choose(&mut rng)
.unwrap(),
"GCP" => TERRAFORM_GCP_RESOURCES_LIST
.iter()
.choose(&mut rng)
.unwrap(),
_ => unreachable!(),
};
let id = TERRAFORM_IDS_LIST.iter().choose(&mut rng).unwrap();
let secs = start.elapsed().as_secs();
match rng.random_range(0..9) {
0 => {
bold(format!("{resource}.{id}: Refreshing state... [id={id}]").as_ref()).await;
}
1 => {
bold(format!("{resource}.{id}: Creating...").as_ref()).await;
}
2 => {
bold(
format!("{resource}.{id}: Creation complete after {secs}s [id={id}]")
.as_ref(),
)
.await;
added += 1;
}
3 => {
bold(format!("{resource}.{id}: Still creating... [{secs}s elapsed]").as_ref())
.await;
}
4 => {
bold(format!("{resource}.{id}: Modifying... [id={id}]").as_ref()).await;
}
5 => {
bold(
format!("{resource}.{id}: Still modifying... [id={id}, {secs}s elapsed]")
.as_ref(),
)
.await;
}
6 => {
bold(
format!("{resource}.{id}: Modifications complete after {secs}s [id={id}]")
.as_ref(),
)
.await;
changed += 1;
}
7 => {
bold(format!("{resource}.{id}: Destroying... [id={id}]").as_ref()).await;
}
8 => {
bold(format!("{resource}.{id}: Destruction complete after {secs}s").as_ref())
.await;
destroyed += 1;
}
_ => {
unreachable!();
}
};
let base_sleep_time_ms = 100.0;
let dist = FisherF::new(5.0, 5.0).unwrap();
let sleep_duration = dist.sample(&mut rng) * base_sleep_time_ms;
csleep(sleep_duration as u64).await;
if appconfig.should_exit() {
print(format!(
"\r\nApply complete! Resources: {added} added, {changed} changed, {destroyed} destroyed.\r\n"
))
.await;
break;
}
}
return;
}
}