Skip to content

Commit e286a67

Browse files
feat: Separate networks per proxy (#82)
1 parent 9cd1978 commit e286a67

File tree

11 files changed

+129
-33
lines changed

11 files changed

+129
-33
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bootstrap/main.tf

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@ module "ogmios_v1_feature" {
2626
resources = var.operator_resources
2727
}
2828

29-
module "ogmios_v1_proxy" {
30-
depends_on = [kubernetes_namespace.namespace]
31-
source = "./proxy"
29+
module "ogmios_v1_proxies_blue" {
30+
depends_on = [kubernetes_namespace.namespace]
31+
source = "./proxy"
32+
for_each = { for network in var.networks : "${network}" => network }
33+
34+
network = each.network
3235
cloud_provider = var.cloud_provider
3336
cluster_issuer = var.cluster_issuer
3437
dns_zone = var.dns_zone
@@ -37,14 +40,16 @@ module "ogmios_v1_proxy" {
3740
extra_annotations = var.proxy_blue_extra_annotations
3841
name = var.proxy_blue_name
3942
namespace = var.namespace
40-
networks = var.networks
4143
proxy_image_tag = var.proxy_blue_image_tag
4244
replicas = var.proxy_blue_replicas
4345
}
4446

45-
module "ogmios_v1_proxy_green" {
46-
depends_on = [kubernetes_namespace.namespace]
47-
source = "./proxy"
47+
module "ogmios_v1_proxies_green" {
48+
depends_on = [kubernetes_namespace.namespace]
49+
source = "./proxy"
50+
for_each = { for network in var.networks : "${network}" => network }
51+
52+
network = each.network
4853
cloud_provider = var.cloud_provider
4954
cluster_issuer = var.cluster_issuer
5055
dns_zone = var.dns_zone
@@ -53,7 +58,6 @@ module "ogmios_v1_proxy_green" {
5358
extra_annotations = var.proxy_green_extra_annotations
5459
name = var.proxy_green_name
5560
namespace = var.namespace
56-
networks = var.networks
5761
proxy_image_tag = var.proxy_green_image_tag
5862
replicas = var.proxy_green_replicas
5963
}

bootstrap/proxy/cert.tf

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11

22

33
locals {
4-
by_network = flatten([
5-
for network in var.networks : [
6-
for version in var.versions : "*.${network}-v${version}.${var.extension_name}.${var.dns_zone}"
7-
]
4+
by_version = flatten([
5+
for version in var.versions : "*.${var.network}-v${version}.${var.extension_name}.${var.dns_zone}"
86
])
97

108
# Add the extra URL to the list of generated URLs
11-
dns_names = concat(local.by_network, ["*.${var.extension_name}.${var.dns_zone}"])
12-
cert_secret_name = var.environment != null ? "${var.extension_name}-${var.environment}-wildcard-tls" : "${var.extension_name}-wildcard-tls"
9+
dns_names = concat(local.by_version, ["*.${var.extension_name}.${var.dns_zone}"])
10+
cert_secret_name = var.environment != null ? "${var.extension_name}-${var.environment}-${var.network}-wildcard-tls" : "${var.extension_name}-${var.network}-wildcard-tls"
1311
}
1412

1513
resource "kubernetes_manifest" "certificate_cluster_wildcard_tls" {

bootstrap/proxy/config.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
locals {
2-
config_map_name = var.environment != null ? "${var.environment}-proxy-config" : "proxy-config"
2+
config_map_name = var.environment != null ? "${var.environment}-proxy-${var.network}-config" : "proxy-${var.network}-config"
33

44
tiers = [
55
{

bootstrap/proxy/deployment.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ resource "kubernetes_deployment_v1" "ogmios_proxy" {
4646
protocol = "TCP"
4747
}
4848

49+
env {
50+
name = "NETWORK"
51+
value = var.network
52+
}
53+
4954
env {
5055
name = "PROXY_NAMESPACE"
5156
value = var.namespace

bootstrap/proxy/main.tf

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
locals {
2-
name = var.name
3-
role = "proxy"
2+
name = var.name != null ? var.name : "proxy-${var.network}"
3+
role = "proxy-${var.network}"
44

55
prometheus_port = 9187
66
prometheus_addr = "0.0.0.0:${local.prometheus_port}"
@@ -12,7 +12,7 @@ locals {
1212

1313
variable "name" {
1414
type = string
15-
default = "proxy"
15+
default = null
1616
}
1717

1818
// blue - green
@@ -72,9 +72,8 @@ variable "extension_name" {
7272
type = string
7373
}
7474

75-
variable "networks" {
76-
type = list(string)
77-
default = ["mainnet", "preprod", "preview", "vector-testnet"]
75+
variable "network" {
76+
type = string
7877
}
7978

8079
variable "versions" {

proxy/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ hyper-util = { version = "0.1.3", features = ["full"] }
1717
leaky-bucket = "1.0.1"
1818
prometheus = "0.13.3"
1919
regex = "1.10.3"
20+
reqwest = { version = "0.11.23", features = ["json"] }
2021
thiserror = "1.0.56"
2122
tokio = { version = "1.35.1", features = ["full"] }
2223
tokio-tungstenite = "0.21.0"

proxy/src/config.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ pub struct Config {
1111
pub ogmios_dns: String,
1212
pub ssl_crt_path: PathBuf,
1313
pub ssl_key_path: PathBuf,
14+
pub network: String,
15+
16+
// Health endpoint
17+
pub health_poll_interval: std::time::Duration,
1418
}
1519

1620
impl Config {
1721
pub fn new() -> Self {
1822
Self {
23+
network: env::var("NETWORK").expect("NETWORK must be set"),
1924
proxy_addr: env::var("PROXY_ADDR").expect("PROXY_ADDR must be set"),
2025
proxy_namespace: env::var("PROXY_NAMESPACE").unwrap_or("ftr-ogmios-v1".into()),
2126
proxy_tiers_path: env::var("PROXY_TIERS_PATH")
@@ -41,6 +46,21 @@ impl Config {
4146
.parse()
4247
.expect("OGMIOS_PORT must a number"),
4348
ogmios_dns: env::var("OGMIOS_DNS").expect("OGMIOS_DNS must be set"),
49+
health_poll_interval: env::var("HEALTH_POLL_INTERVAL")
50+
.map(|v| {
51+
Duration::from_secs(
52+
v.parse::<u64>()
53+
.expect("HEALTH_POLL_INTERVAL must be a number in seconds. eg: 2"),
54+
)
55+
})
56+
.unwrap_or(Duration::from_secs(10)),
4457
}
4558
}
59+
60+
pub fn instance(&self, version: &str) -> String {
61+
format!(
62+
"ogmios-{}-{}.{}:{}",
63+
self.network, version, self.ogmios_dns, self.ogmios_port
64+
)
65+
}
4666
}

proxy/src/health.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use std::sync::Arc;
2+
use tracing::{error, info, warn};
3+
4+
use crate::State;
5+
6+
async fn get_health(state: &State) -> bool {
7+
let client = match reqwest::Client::builder().build() {
8+
Ok(client) => client,
9+
Err(err) => {
10+
warn!(error = err.to_string(), "Failed to build reqwest client");
11+
return false;
12+
}
13+
};
14+
15+
let response = match client
16+
.get(format!("http://{}/health", state.config.instance("6")))
17+
.send()
18+
.await
19+
{
20+
Ok(response) => response,
21+
Err(err) => {
22+
warn!(error = err.to_string(), "Failed to perform health request");
23+
return false;
24+
}
25+
};
26+
27+
let status = response.status();
28+
if status.is_client_error() || status.is_server_error() {
29+
error!(status = status.to_string(), "Health request failed");
30+
return false;
31+
}
32+
33+
status == 200
34+
}
35+
36+
async fn update_health(state: &State) {
37+
let current_health = *state.upstream_health.read().await;
38+
39+
let new_health = get_health(state).await;
40+
41+
match (current_health, new_health) {
42+
(false, true) => info!("Upstream is now healthy, ready to proxy requests."),
43+
(true, false) => warn!("Upstream is now deamed unhealthy."),
44+
_ => {}
45+
}
46+
47+
*state.upstream_health.write().await = new_health;
48+
}
49+
50+
pub async fn start(state: Arc<State>) {
51+
loop {
52+
update_health(&state).await;
53+
tokio::time::sleep(state.config.health_poll_interval).await;
54+
}
55+
}

proxy/src/main.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use tracing::Level;
1515

1616
mod auth;
1717
mod config;
18+
mod health;
1819
mod limiter;
1920
mod metrics;
2021
mod proxy;
@@ -34,8 +35,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3435

3536
let metrics = metrics::start(state.clone());
3637
let proxy_server = proxy::start(state.clone());
38+
let healthloop = health::start(state.clone());
3739

38-
tokio::join!(metrics, proxy_server);
40+
tokio::join!(metrics, proxy_server, healthloop);
3941

4042
Ok(())
4143
}
@@ -47,6 +49,7 @@ pub struct State {
4749
consumers: RwLock<HashMap<String, Consumer>>,
4850
tiers: RwLock<HashMap<String, Tier>>,
4951
limiter: RwLock<HashMap<String, Vec<Arc<RateLimiter>>>>,
52+
upstream_health: RwLock<bool>,
5053
}
5154
impl State {
5255
pub fn try_new() -> Result<Self, Box<dyn Error>> {
@@ -64,6 +67,7 @@ impl State {
6467
consumers,
6568
tiers,
6669
limiter,
70+
upstream_health: RwLock::new(false),
6771
})
6872
}
6973

0 commit comments

Comments
 (0)