use crate::core::error::{Error, Result};
use crate::core::remote::CloudProvider;
use crate::core::resources::ResourceSpec;
use crate::infra::traits::{BlueprintDeploymentResult, CloudProviderAdapter};
use crate::infra::types::{InstanceStatus, ProvisionedInstance};
use crate::providers::common::gpu_adapter::build_http_client;
use crate::security::ApiAuthentication;
use async_trait::async_trait;
use blueprint_core::info;
use blueprint_std::collections::HashMap;
pub struct CoreWeaveAdapter {
default_region: String,
namespace: String,
token: String,
}
impl CoreWeaveAdapter {
pub async fn new() -> Result<Self> {
let token = std::env::var("COREWEAVE_TOKEN")
.map_err(|_| Error::Other("COREWEAVE_TOKEN environment variable not set".into()))?;
let default_region =
std::env::var("COREWEAVE_REGION").unwrap_or_else(|_| "ORD1".to_string());
let namespace =
std::env::var("COREWEAVE_NAMESPACE").unwrap_or_else(|_| "tenant-blueprint".to_string());
Ok(Self {
default_region,
namespace,
token,
})
}
fn logical_instance_id(&self) -> String {
format!("{}-{}", self.namespace, uuid::Uuid::new_v4())
}
#[allow(dead_code)]
fn token(&self) -> &str {
&self.token
}
}
#[async_trait]
impl CloudProviderAdapter for CoreWeaveAdapter {
async fn provision_instance(
&self,
instance_type: &str,
region: &str,
_require_tee: bool,
) -> Result<ProvisionedInstance> {
let resolved_region = if region.is_empty() {
self.default_region.as_str()
} else {
region
};
let id = self.logical_instance_id();
info!(%id, %resolved_region, %instance_type, "Reserved CoreWeave logical deployment slot");
Ok(ProvisionedInstance {
id,
provider: CloudProvider::CoreWeave,
instance_type: instance_type.to_string(),
region: resolved_region.to_string(),
public_ip: None,
private_ip: None,
status: InstanceStatus::Starting,
})
}
async fn terminate_instance(&self, instance_id: &str) -> Result<()> {
info!(%instance_id, "CoreWeave logical slot released");
Ok(())
}
async fn get_instance_status(&self, _instance_id: &str) -> Result<InstanceStatus> {
Ok(InstanceStatus::Running)
}
async fn deploy_blueprint_with_target(
&self,
target: &crate::core::deployment_target::DeploymentTarget,
blueprint_image: &str,
resource_spec: &ResourceSpec,
env_vars: HashMap<String, String>,
) -> Result<BlueprintDeploymentResult> {
use crate::core::deployment_target::DeploymentTarget;
match target {
DeploymentTarget::GenericKubernetes {
context: _,
namespace,
} => {
#[cfg(feature = "kubernetes")]
{
use crate::shared::SharedKubernetesDeployment;
let ns = if namespace.is_empty() {
self.namespace.as_str()
} else {
namespace.as_str()
};
SharedKubernetesDeployment::deploy_to_generic_k8s(
ns,
blueprint_image,
resource_spec,
env_vars,
)
.await
}
#[cfg(not(feature = "kubernetes"))]
{
let _ = (namespace, blueprint_image, resource_spec, env_vars);
Err(Error::ConfigurationError(
"CoreWeave adapter requires the `kubernetes` feature".into(),
))
}
}
DeploymentTarget::ManagedKubernetes {
cluster_id: _,
namespace,
} => {
#[cfg(feature = "kubernetes")]
{
use crate::shared::SharedKubernetesDeployment;
let ns = if namespace.is_empty() {
self.namespace.as_str()
} else {
namespace.as_str()
};
SharedKubernetesDeployment::deploy_to_generic_k8s(
ns,
blueprint_image,
resource_spec,
env_vars,
)
.await
}
#[cfg(not(feature = "kubernetes"))]
{
let _ = (namespace, blueprint_image, resource_spec, env_vars);
Err(Error::ConfigurationError(
"CoreWeave adapter requires the `kubernetes` feature".into(),
))
}
}
DeploymentTarget::VirtualMachine { .. } => Err(Error::ConfigurationError(
"CoreWeave does not provision raw VMs — use GenericKubernetes target".into(),
)),
DeploymentTarget::Serverless { .. } => Err(Error::ConfigurationError(
"CoreWeave has no serverless offering".into(),
)),
}
}
async fn deploy_blueprint(
&self,
_instance: &ProvisionedInstance,
blueprint_image: &str,
resource_spec: &ResourceSpec,
env_vars: HashMap<String, String>,
) -> Result<BlueprintDeploymentResult> {
#[cfg(feature = "kubernetes")]
{
use crate::shared::SharedKubernetesDeployment;
SharedKubernetesDeployment::deploy_to_generic_k8s(
&self.namespace,
blueprint_image,
resource_spec,
env_vars,
)
.await
}
#[cfg(not(feature = "kubernetes"))]
{
let _ = (blueprint_image, resource_spec, env_vars);
Err(Error::ConfigurationError(
"CoreWeave adapter requires the `kubernetes` feature".into(),
))
}
}
async fn health_check_blueprint(&self, deployment: &BlueprintDeploymentResult) -> Result<bool> {
if let Some(endpoint) = deployment.qos_grpc_endpoint() {
let client = build_http_client()?;
match client
.get(&format!("{endpoint}/health"), &ApiAuthentication::None)
.await
{
Ok(response) => Ok(response.status().is_success()),
Err(_) => Ok(false),
}
} else {
Ok(false)
}
}
async fn cleanup_blueprint(&self, _deployment: &BlueprintDeploymentResult) -> Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_adapter(namespace: &str) -> CoreWeaveAdapter {
CoreWeaveAdapter {
default_region: "ORD1".into(),
namespace: namespace.into(),
token: "test-token".into(),
}
}
#[test]
fn logical_id_is_namespace_scoped() {
let adapter = test_adapter("tenant-test");
let id = adapter.logical_instance_id();
assert!(id.starts_with("tenant-test-"));
assert!(id.len() > "tenant-test-".len() + 20);
}
#[test]
fn logical_id_differs_between_calls() {
let adapter = test_adapter("tenant-x");
let a = adapter.logical_instance_id();
let b = adapter.logical_instance_id();
assert_ne!(a, b);
}
#[test]
fn token_accessor_returns_configured_value() {
let adapter = test_adapter("tenant-y");
assert_eq!(adapter.token(), "test-token");
}
}