use cloud_terrastodon_azure::AzureTenantId;
use cloud_terrastodon_azure::fetch_all_policy_assignments;
use cloud_terrastodon_azure::fetch_all_policy_definitions;
use cloud_terrastodon_azure::fetch_all_policy_set_definitions;
use cloud_terrastodon_azure::fetch_all_subscriptions;
use cloud_terrastodon_hcl::HclImportBlock;
use cloud_terrastodon_hcl::HclProviderReference;
use cloud_terrastodon_hcl::HclWriter;
use cloud_terrastodon_hcl::ProviderKind;
use cloud_terrastodon_hcl::Sanitizable;
use cloud_terrastodon_pathing::AppDir;
use eyre::Result;
use eyre::eyre;
use std::collections::HashMap;
use std::collections::HashSet;
use tokio::try_join;
use tracing::info;
pub async fn build_policy_imports(tenant_id: AzureTenantId) -> Result<()> {
info!("Fetching information");
let (policy_definitions, policy_set_definitions, policy_assignments, subscriptions) = try_join!(
fetch_all_policy_definitions(tenant_id),
fetch_all_policy_set_definitions(tenant_id),
fetch_all_policy_assignments(tenant_id),
fetch_all_subscriptions(tenant_id),
)?;
let subscriptions = subscriptions
.into_iter()
.map(|sub| (sub.id, sub))
.collect::<HashMap<_, _>>();
let mut imports: Vec<HclImportBlock> = Default::default();
let mut seen_ids: HashSet<String> = HashSet::new();
let mut provider_blocks: HashSet<_> = Default::default();
info!("Writing policy definition import blocks");
for policy_definition in policy_definitions {
if policy_definition.policy_type == "Custom" {
let provider = if let Some(subscription_id) = policy_definition.id.subscription_id() {
let subscription = subscriptions.get(&subscription_id).ok_or(eyre!(format!(
"Could not find subscription with id {}",
&subscription_id
)))?;
let azurerm_provider_block = subscription.into_provider_block();
provider_blocks.insert(azurerm_provider_block.clone());
HclProviderReference::Alias {
kind: ProviderKind::AzureRM,
name: subscription.name.sanitize(),
}
} else {
HclProviderReference::Inherited
};
let mut block: HclImportBlock = policy_definition.into();
block.provider = provider;
if seen_ids.insert(block.id.clone()) {
imports.push(block);
}
}
}
info!("Writing policy set definition import blocks");
for policy_set_definition in policy_set_definitions {
if policy_set_definition.policy_type == "Custom" {
let provider =
if let Some(subscription_id) = policy_set_definition.id.subscription_id() {
let subscription = subscriptions.get(&subscription_id).ok_or(eyre!(
format!("Could not find subscription with id {}", &subscription_id)
))?;
let azurerm_provider_block = subscription.into_provider_block();
provider_blocks.insert(azurerm_provider_block.clone());
HclProviderReference::Alias {
kind: ProviderKind::AzureRM,
name: subscription.name.sanitize(),
}
} else {
HclProviderReference::Inherited
};
let mut block: HclImportBlock = policy_set_definition.into();
block.provider = provider;
if seen_ids.insert(block.id.clone()) {
imports.push(block);
}
}
}
info!("Writing policy assignment import blocks");
for policy_assignment in policy_assignments {
let import_block: HclImportBlock = policy_assignment.into();
let provider = import_block.provider;
let id = import_block.id;
let to = import_block.to;
let block = HclImportBlock { provider, id, to };
if seen_ids.insert(block.id.clone()) {
imports.push(block);
}
}
if imports.is_empty() {
return Err(eyre!("Imports should not be empty"));
}
info!("Writing boilerplate.tf");
HclWriter::new(AppDir::Imports.join("boilerplate.tf"))
.format_on_write()
.merge(provider_blocks)
.await?;
info!("Writing policy_imports.tf");
HclWriter::new(AppDir::Imports.join("policy_imports.tf"))
.format_on_write()
.overwrite(imports)
.await?;
Ok(())
}