Skip to content

Commit

Permalink
feat: nat-traversal by detect public_ip from cloud metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
giangndm committed Nov 18, 2024
1 parent 9f6bdca commit f16a6e0
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
40 changes: 39 additions & 1 deletion bin/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::{net::SocketAddr, str::FromStr};
use std::{
net::{IpAddr, SocketAddr},
str::FromStr,
};

use atm0s_sdn::{NodeAddr, NodeId};
use clap::ValueEnum;
use media_server_protocol::cluster::ZoneId;

mod errors;
Expand Down Expand Up @@ -33,3 +37,37 @@ pub async fn fetch_node_addr_from_api(url: &str) -> Result<NodeAddr, String> {
.ok_or(format!("No data in response from {}", url))?;
NodeAddr::from_str(&node_addr).map_err(|e| e.to_string())
}

#[derive(Debug, Clone, ValueEnum)]
pub enum CloudProvider {
Aws,
Gcp,
Azure,
Other,
}

pub async fn fetch_node_ip_alt_from_cloud(cloud: CloudProvider) -> Result<IpAddr, String> {
match cloud {
CloudProvider::Aws => {
let resp = reqwest::get("http://169.254.169.254/latest/meta-data/local-ipv4").await.map_err(|e| e.to_string())?;
let ip = resp.text().await.map_err(|e| e.to_string())?;
IpAddr::from_str(&ip).map_err(|e| e.to_string())
}
CloudProvider::Gcp => {
let client = reqwest::Client::new();
let resp = client
.get("http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip")
.header("Metadata-Flavor", "Google")
.send()
.await
.map_err(|e| e.to_string())?;
let ip = resp.text().await.map_err(|e| e.to_string())?;
IpAddr::from_str(&ip).map_err(|e| e.to_string())
}
CloudProvider::Azure | CloudProvider::Other => {
let resp = reqwest::get("http://ipv4.icanhazip.com").await.map_err(|e| e.to_string())?;
let ip = resp.text().await.map_err(|e| e.to_string())?;
IpAddr::from_str(&ip).map_err(|e| e.to_string())
}
}
}
16 changes: 15 additions & 1 deletion bin/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::net::{IpAddr, SocketAddr};

use atm0s_media_server::{fetch_node_addr_from_api, server, NodeConfig};
use atm0s_media_server::{fetch_node_ip_alt_from_cloud, CloudProvider};
use atm0s_sdn::NodeAddr;
use clap::Parser;
use media_server_protocol::cluster::ZoneId;
Expand Down Expand Up @@ -45,6 +46,10 @@ struct Args {
#[arg(env, long)]
node_ip_alt: Vec<IpAddr>,

/// Auto detect node_ip_alt with some common cloud provider metadata.
#[arg(env, long)]
node_ip_alt_cloud: Option<CloudProvider>,

/// Enable private IP addresses for the node.
#[arg(env, long)]
enable_private_ip: bool,
Expand Down Expand Up @@ -125,6 +130,11 @@ async fn main() {
}
}

let mut node_ip_alt_cloud = vec![];
if let Some(cloud) = args.node_ip_alt_cloud {
node_ip_alt_cloud.push(fetch_node_ip_alt_from_cloud(cloud).await.expect("should get node ip alt"));
}

let bind_addrs = if let Some(ip) = args.node_ip {
vec![SocketAddr::new(ip, sdn_port)]
} else {
Expand All @@ -147,7 +157,11 @@ async fn main() {
seeds: args.seeds,
bind_addrs,
zone: ZoneId(args.sdn_zone_id),
bind_addrs_alt: args.node_ip_alt.into_iter().map(|ip| SocketAddr::new(ip, sdn_port)).collect::<Vec<_>>(),
bind_addrs_alt: node_ip_alt_cloud
.into_iter()
.chain(args.node_ip_alt.into_iter())
.map(|ip| SocketAddr::new(ip, sdn_port))
.collect::<Vec<_>>(),
};

log::info!("Bind addrs {:?}, bind addrs alt {:?}", node.bind_addrs, node.bind_addrs_alt);
Expand Down
20 changes: 20 additions & 0 deletions docs/getting-started/installation/nat-traversal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# NAT Traversal

Some cloud providers (like AWS) route all traffic through a NAT gateway, which means that we don't have a public IP address on the VM.

To work around this, we can use the `node_ip_alt` and `node_ip_alt_cloud` options to specify alternative IP addresses for the node.

## Using node_ip_alt

The `node_ip_alt` option takes a list of IP addresses as input, and the node will bind to each of them.

## Using node_ip_alt_cloud

The `node_ip_alt_cloud` option takes a cloud provider as input, and will automatically fetch the alternative IP address for the node.

| Cloud Provider | Fetch URL |
| -------------- | ----------------------------------------------------------------------------------------------- |
| AWS | `http://169.254.169.254/latest/meta-data/local-ipv4` |
| GCP | `http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip` |
| Azure | `http://ipv4.icanhazip.com` |
| Other | `http://ipv4.icanhazip.com` |

0 comments on commit f16a6e0

Please sign in to comment.