pub mod gpu_adapter;
use crate::core::remote::CloudProvider;
use async_trait::async_trait;
use blueprint_std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InstanceSelection {
pub instance_type: String,
pub spot_capable: bool,
pub estimated_hourly_cost: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProvisioningConfig {
pub name: String,
pub region: String,
pub ssh_key_name: Option<String>,
pub ami_id: Option<String>,
pub machine_image: Option<String>,
pub custom_config: HashMap<String, String>,
}
impl Default for ProvisioningConfig {
fn default() -> Self {
Self {
name: "blueprint-deployment".to_string(),
region: "us-west-2".to_string(),
ssh_key_name: None,
ami_id: None,
machine_image: None,
custom_config: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProvisionedInfrastructure {
pub provider: CloudProvider,
pub instance_id: String,
pub public_ip: Option<String>,
pub private_ip: Option<String>,
pub region: String,
pub instance_type: String,
pub metadata: HashMap<String, String>,
}
impl ProvisionedInfrastructure {
pub async fn is_ready(&self) -> bool {
let has_network = self.public_ip.is_some() || self.private_ip.is_some();
if !has_network {
return false;
}
if let Some(endpoint) = self.get_endpoint() {
self.check_port_open(&endpoint, 22).await
} else {
false
}
}
async fn check_port_open(&self, host: &str, port: u16) -> bool {
use blueprint_std::time::Duration;
use tokio::net::TcpStream;
use tokio::time::timeout;
let addr = format!("{host}:{port}");
matches!(
timeout(Duration::from_secs(5), TcpStream::connect(&addr)).await,
Ok(Ok(_))
)
}
pub fn get_endpoint(&self) -> Option<String> {
self.public_ip.clone().or_else(|| self.private_ip.clone())
}
pub fn into_provisioned_instance(self) -> crate::infra::types::ProvisionedInstance {
crate::infra::types::ProvisionedInstance {
id: self.instance_id,
provider: self.provider,
instance_type: self.instance_type,
region: self.region,
public_ip: self.public_ip,
private_ip: self.private_ip,
status: crate::infra::types::InstanceStatus::Running,
}
}
}
#[async_trait]
pub trait CloudProvisioner: Send + Sync {
type Config: Clone + Send + Sync;
type Instance: Clone + Send + Sync;
async fn new(config: Self::Config) -> crate::core::error::Result<Self>
where
Self: Sized;
async fn provision_instance(
&self,
spec: &crate::core::resources::ResourceSpec,
config: &ProvisioningConfig,
) -> crate::core::error::Result<ProvisionedInfrastructure>;
async fn terminate_instance(&self, instance_id: &str) -> crate::core::error::Result<()>;
}