use anyhow::Result;
use async_trait::async_trait;
pub mod cloudflare;
pub use cloudflare::{
CfAccountInfo, CloudflareClient, CreateR2BucketResult, CreateTokenResult, CreateTunnelResult,
DnsRecordDetail, GrantScope, R2BucketInfo, R2CustomDomain, TokenGrant, TunnelConnState,
TunnelDnsRecord, TunnelDriftRow, TunnelDriftState, WorkerDeployResult, DOOR_DNS_GRANTS,
MESOFACT_STATIC_GRANTS, R2_BUCKET_READ_GRANTS, R2_BUCKET_RW_GRANTS, TUNNEL_EDIT_GRANTS,
};
pub mod hetzner;
pub use hetzner::HetznerDriver;
pub mod cloudflare_envoy;
pub use cloudflare_envoy::CloudflareEnvoy;
pub mod hetzner_envoy;
pub use hetzner_envoy::HetznerEnvoy;
pub mod digitalocean;
pub use digitalocean::{DigitalOceanClient, DigitalOceanEnvoy, DoCreateDropletSpec};
pub mod floating_ip;
pub use floating_ip::{
on_ingress_owner_changed, reconcile_assignment, FloatingIpAssignOutcome, FloatingIpProvider,
FloatingIpState, FloatingIpTarget,
};
pub use floating_ip::{
floating_ip_provider_for, plan_ingress_owner_effect, provider_has_floating_ip_adapter,
resolve_ingress_owner, IngressOwnerEffect, OwnerLiveness, QuorumHealth,
};
pub use floating_ip_adapters::{HetznerFloatingIp, OvhFloatingIp, VultrFloatingIp};
pub mod floating_ip_envoy;
pub use floating_ip_envoy::{dispatch_floating_ip_verb, FloatingIpEnvoy};
#[cfg(feature = "local-docker")]
pub mod local_docker;
#[cfg(feature = "local-docker")]
pub use local_docker::LocalDockerProvider;
#[cfg(feature = "local-docker")]
pub mod local_docker_envoy;
#[cfg(feature = "local-docker")]
pub use local_docker_envoy::LocalDockerEnvoy;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ProjectId(pub String);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ServerId(pub String);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BucketRef {
pub name: String,
pub endpoint: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ServerStatus {
Initializing,
Starting,
Running,
Stopping,
Off,
Deleting,
Unknown(String),
}
impl ServerStatus {
pub fn is_running(&self) -> bool {
matches!(self, ServerStatus::Running)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServerSummary {
pub id: ServerId,
pub server_type: String,
pub status: ServerStatus,
pub public_ipv4: Option<String>,
pub location: String,
}
#[derive(Debug, Clone)]
pub struct ServerSpec {
pub name: String,
pub server_type: String,
pub image: String,
pub location: Location,
pub ssh_keys: Vec<u64>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Location {
Pdx,
Iad,
Fsn,
}
impl Location {
pub fn hetzner_cloud_id(&self) -> &'static str {
match self {
Location::Pdx => "hil",
Location::Iad => "ash",
Location::Fsn => "fsn1",
}
}
pub fn hetzner_storage_endpoint(&self) -> &'static str {
match self {
Location::Fsn => "https://fsn1.your-objectstorage.com",
Location::Pdx => "https://hil.your-objectstorage.com",
Location::Iad => "https://ash.your-objectstorage.com",
}
}
pub fn hetzner_storage_region(&self) -> &'static str {
match self {
Location::Fsn => "fsn1",
Location::Pdx => "hil",
Location::Iad => "ash",
}
}
}
impl TryFrom<&str> for Location {
type Error = anyhow::Error;
fn try_from(s: &str) -> Result<Self> {
match s {
"na-west" | "pdx" | "hil" => Ok(Location::Pdx),
"na-east" | "iad" | "ash" => Ok(Location::Iad),
"eu-central" | "fsn" | "fsn1" => Ok(Location::Fsn),
other => Err(anyhow::anyhow!("unknown location: {other}")),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BucketAcl {
Private,
PublicRead,
}
impl BucketAcl {
pub fn as_canned(&self) -> &'static str {
match self {
BucketAcl::Private => "private",
BucketAcl::PublicRead => "public-read",
}
}
}
#[async_trait]
pub trait MachineProvider: Send + Sync {
async fn ensure_project(&self, name: &str) -> Result<ProjectId>;
async fn create_server(
&self,
project: &ProjectId,
spec: &ServerSpec,
user_data: &str,
) -> Result<ServerId>;
async fn create_bucket(&self, name: &str, location: Location) -> Result<BucketRef>;
async fn server_status(&self, id: &ServerId) -> Result<ServerStatus>;
async fn find_server_by_name(&self, name: &str) -> Result<Option<ServerSummary>>;
async fn bucket_exists(&self, name: &str, location: Location) -> Result<bool>;
async fn destroy_server(&self, id: &ServerId) -> Result<()>;
async fn delete_bucket(&self, name: &str, location: Location) -> Result<()>;
async fn set_bucket_acl(&self, name: &str, location: Location, acl: BucketAcl) -> Result<()>;
}