use blueprint_remote_providers::DeploymentTracker;
use clap::Subcommand;
use color_eyre::{
Result,
eyre::{WrapErr, eyre},
};
use std::path::PathBuf;
mod config;
mod json;
mod schema;
pub use schema::{MAX_JSON_BYTES, SCHEMA_VERSION};
mod estimate;
mod policy;
mod preflight;
mod status;
pub use config::CloudProvider;
pub use policy::{CostOptimization, RemoteDeploymentPolicy};
#[derive(Subcommand, Debug)]
pub enum CloudCommands {
Catalog {
#[arg(long, required = true)]
json: bool,
},
Quote {
#[arg(long, required = true)]
json: bool,
},
Create {
#[arg(long, required = true)]
json: bool,
},
Recover {
#[arg(long, required = true)]
json: bool,
},
StateInit {
#[arg(long, required = true)]
json: bool,
},
Destroy {
#[arg(long, required = true)]
json: bool,
},
#[command(visible_alias = "cfg")]
Configure {
provider: CloudProvider,
#[arg(short, long)]
region: Option<String>,
#[arg(short = 'd', long)]
set_default: bool,
},
#[command(visible_alias = "policy")]
ConfigurePolicy {
#[command(flatten)]
args: policy::PolicyConfigureArgs,
},
#[command(visible_alias = "show")]
ShowPolicy,
#[command(visible_alias = "cost")]
Estimate(estimate::EstimateOptions),
#[command(visible_alias = "s")]
Status {
#[arg(long, conflicts_with_all = ["service_id", "watch"])]
json: bool,
service_id: Option<String>,
#[arg(short, long)]
watch: bool,
},
#[command(visible_alias = "term")]
Terminate {
#[arg(required_unless_present = "all")]
service_id: Option<String>,
#[arg(long, conflicts_with = "service_id")]
all: bool,
#[arg(short, long)]
yes: bool,
},
#[command(visible_alias = "ls")]
List {
#[arg(long)]
json: bool,
},
#[command(visible_alias = "check")]
Preflight {
#[arg(short, long)]
provider: Option<CloudProvider>,
#[arg(long)]
tee_required: bool,
#[arg(long)]
bootstrap_env: bool,
#[arg(long)]
write_env_file: Option<PathBuf>,
},
}
impl CloudCommands {
pub fn is_json(&self) -> bool {
matches!(
self,
Self::Catalog { .. }
| Self::Quote { .. }
| Self::Create { .. }
| Self::Recover { .. }
| Self::StateInit { .. }
| Self::Destroy { .. }
| Self::Status { json: true, .. }
| Self::List { json: true }
)
}
}
async fn open_tracker() -> Result<DeploymentTracker> {
let path = std::env::var_os("TANGLE_DEPLOYMENT_TRACKER_PATH")
.map(PathBuf::from)
.or_else(|| dirs::home_dir().map(|home| home.join(".tangle/remote_deployments")))
.ok_or_else(|| eyre!("Could not find the home directory"))?;
DeploymentTracker::new(&path)
.await
.wrap_err("Failed to read the deployment tracker")
}
pub async fn execute(command: CloudCommands) -> Result<()> {
match command {
CloudCommands::Catalog { .. } => json::execute(json::Operation::Catalog).await,
CloudCommands::Quote { .. } => json::execute(json::Operation::Quote).await,
CloudCommands::Create { .. } => json::execute(json::Operation::Create).await,
CloudCommands::Recover { .. } => json::execute(json::Operation::Recover).await,
CloudCommands::StateInit { .. } => json::execute(json::Operation::StateInit).await,
CloudCommands::Destroy { .. } => json::execute(json::Operation::Destroy).await,
CloudCommands::Status { json: true, .. } => json::execute(json::Operation::Status).await,
CloudCommands::List { json: true } => json::execute(json::Operation::List).await,
CloudCommands::Configure {
provider,
region,
set_default,
} => config::configure(provider, region, set_default).await,
CloudCommands::ConfigurePolicy { args } => policy::configure_policy(args).await,
CloudCommands::ShowPolicy => policy::show_policy().await,
CloudCommands::Estimate(options) => estimate::estimate(options).await,
CloudCommands::Status {
service_id,
watch,
json: false,
} => status::show_status(service_id, watch).await,
CloudCommands::Terminate {
service_id,
all: _,
yes,
} => status::terminate(service_id, yes).await,
CloudCommands::List { json: false } => config::list_providers().await,
CloudCommands::Preflight {
provider,
tee_required,
bootstrap_env,
write_env_file,
} => preflight::run(provider, tee_required, bootstrap_env, write_env_file).await,
}
}