diff --git a/README.md b/README.md index f98b893..e1da358 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Usage: robotlb [OPTIONS] --hcloud-token Options: -t, --hcloud-token - `HCloud` API token [env: ROBOTLB_HCLOUD_TOKEN=nY1eU1iMeAd63eRhHRmubQCsRqhGGJoVNK7JmqfxG33SbJZkfdIw5xvf4vfdbQHu] + `HCloud` API token [env: ROBOTLB_HCLOUD_TOKEN=] --dynamic-node-selector If enabled, the operator will try to find target nodes based on where the target pods are actually deployed. If disabled, the operator will try to find target nodes based on the node selector [env: ROBOTLB_DYNAMIC_NODE_SELECTOR=] --default-lb-retries @@ -91,6 +91,9 @@ metadata: # Hetzner cloud network. If this annotation is missing, the operator will try to # assign external IPs to the load balancer if available. Otherwise, the update won't happen. robotlb/lb-network: "my-net" + # Requests specific IP address for the load balancer in the private network. If not specified, + # a random one is given. This parameter does nothing in case if network is not specified. + robotlb/lb-private-ip: "10.10.10.10" # Node selector for the loadbalancer. This is only required if ROBOTLB_DYNAMIC_NODE_SELECTOR # is set to false. If not specified then, all nodes will be selected as LB targets by default. # This property helps you filter out nodes. diff --git a/src/config.rs b/src/config.rs index 5db834c..f848107 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,6 +7,11 @@ pub struct OperatorConfig { #[arg(short = 't', long, env = "ROBOTLB_HCLOUD_TOKEN")] pub hcloud_token: String, + // Default network to use for load balancers. + // If not set, then only network from the service annotation will be used. + #[arg(long, env = "ROBOTLB_DEFAULT_NETWORK", default_value = None)] + pub default_network: Option, + /// If enabled, the operator will try to find target nodes based on where the target pods are actually deployed. /// If disabled, the operator will try to find target nodes based on the node selector. #[arg(long, env = "ROBOTLB_DYNAMIC_NODE_SELECTOR", default_value = "true")] diff --git a/src/consts.rs b/src/consts.rs index f7eca82..9570928 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -8,6 +8,7 @@ pub const LB_TIMEOUT_ANN_NAME: &str = "robotlb/lb-timeout"; pub const LB_RETRIES_ANN_NAME: &str = "robotlb/lb-retries"; pub const LB_PROXY_MODE_LABEL_NAME: &str = "robotlb/lb-proxy-mode"; pub const LB_NETWORK_LABEL_NAME: &str = "robotlb/lb-network"; +pub const LB_PRIVATE_IP_LABEL_NAME: &str = "robotlb/lb-private-ip"; pub const LB_LOCATION_LABEL_NAME: &str = "robotlb/lb-location"; pub const LB_ALGORITHM_LABEL_NAME: &str = "robotlb/lb-algorithm"; diff --git a/src/lb.rs b/src/lb.rs index 3fc1ad5..0ffde3b 100644 --- a/src/lb.rs +++ b/src/lb.rs @@ -45,6 +45,7 @@ pub struct LoadBalancer { pub name: String, pub services: HashMap, pub targets: Vec, + pub private_ip: Option, pub check_interval: i32, pub timeout: i32, @@ -123,6 +124,7 @@ impl LoadBalancer { let network_name = svc .annotations() .get(consts::LB_NETWORK_LABEL_NAME) + .or(context.config.default_network.as_ref()) .cloned(); let name = svc @@ -131,8 +133,14 @@ impl LoadBalancer { .cloned() .unwrap_or(svc.name_any()); + let private_ip = svc + .annotations() + .get(consts::LB_PRIVATE_IP_LABEL_NAME) + .cloned(); + Ok(Self { name, + private_ip, balancer_type, check_interval, timeout, @@ -413,9 +421,20 @@ impl LoadBalancer { let Some(private_net_id) = private_net.network else { continue; }; + // The load balancer is attached to a target network. if desired_network == Some(private_net_id) { - contain_desired_network = true; - continue; + // Specific IP was provided, we need to check if the IP is the same. + if self.private_ip.is_some() { + // if IPs match, we can leave everything as it is. + if private_net.ip == self.private_ip { + contain_desired_network = true; + continue; + } + } else { + // No specific IP was provided, we can leave everything as it is. + contain_desired_network = true; + continue; + } } tracing::info!("Detaching balancer from network {}", private_net_id); hcloud::apis::load_balancers_api::detach_load_balancer_from_network( @@ -443,7 +462,7 @@ impl LoadBalancer { id: hcloud_balancer.id, attach_load_balancer_to_network_request: Some( AttachLoadBalancerToNetworkRequest { - ip: None, + ip: self.private_ip.clone(), network: network_id, }, ), @@ -542,8 +561,6 @@ impl LoadBalancer { if let Some(balancer) = hcloud_lb { return Ok(balancer); } - let network = self.get_network().await?; - let network_id = network.map(|n| n.id); let response = hcloud::apis::load_balancers_api::create_load_balancer( &self.hcloud_config, @@ -554,7 +571,7 @@ impl LoadBalancer { load_balancer_type: self.balancer_type.clone(), location: Some(self.location.clone()), name: self.name.clone(), - network: network_id, + network: None, network_zone: None, public_interface: Some(true), services: Some(vec![]),