This guide teaches you step-by-step how to implement support for a new cloud provider in spuff. We'll use Hetzner Cloud as an example, but the concepts apply to any provider.
// src/provider/config.rs
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ProviderType {
DigitalOcean,
Hetzner, // ← Add here
Aws,
}
impl ProviderType {
/// Returns whether the provider is implemented and ready to use
pub fn is_implemented(&self) -> bool {
matches!(self,
Self::DigitalOcean
| Self::Hetzner // ← Add here when implemented
)
}
/// Provider name as string (used in configs and CLI)
pub fn as_str(&self) -> &'static str {
match self {
Self::DigitalOcean => "digitalocean",
Self::Hetzner => "hetzner", // ← Add here
Self::Aws => "aws",
}
}
/// Environment variable for the API token
pub fn token_env_var(&self) -> &'static str {
match self {
Self::DigitalOcean => "DIGITALOCEAN_TOKEN",
Self::Hetzner => "HETZNER_TOKEN", // ← Add here
Self::Aws => "AWS_ACCESS_KEY_ID",
}
}
}
touch src/provider/hetzner.rs
// src/provider/hetzner.rs
//! Hetzner Cloud Provider
//!
//! Provider implementation for Hetzner Cloud.
//! API Documentation: https://docs.hetzner.cloud/
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
use std::time::Instant;
use super::{
ImageSpec, InstanceRequest, InstanceStatus, Provider, ProviderInstance,
ProviderResult, Snapshot,
};
use super::config::ProviderTimeouts;
use super::error::ProviderError;
use super::registry::{ProviderFactory, ProviderType};
/// Hetzner Cloud API base URL
const API_BASE: &str = "https://api.hetzner.cloud/v1";
// =============================================================================
// Provider Struct
// =============================================================================
/// Hetzner Cloud provider
pub struct HetznerProvider {
client: Client,
token: String,
base_url: String,
timeouts: ProviderTimeouts,
}
// =============================================================================
// Factory Struct
// =============================================================================
/// Factory for creating HetznerProvider instances
pub struct HetznerFactory;
// ... implementations below
// src/provider/mod.rs
mod config;
mod digitalocean;
mod error;
mod hetzner; // ← Add here
mod registry;
pub use hetzner::{HetznerFactory, HetznerProvider}; // ← And here