Skip to content

Commit 71c152c

Browse files
committed
Split node_primary_addresses into a separate module
1 parent 8ebd837 commit 71c152c

File tree

4 files changed

+125
-116
lines changed

4 files changed

+125
-116
lines changed

rust/operator-binary/src/csi_server/node.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
listener_mounted_pod_label, listener_persistent_volume_label, ListenerMountedPodLabelError,
2222
ListenerPersistentVolumeLabelError,
2323
},
24-
utils::{error_full_message, node_primary_address},
24+
utils::{address::node_primary_addresses, error_full_message},
2525
};
2626

2727
use super::{tonic_unimplemented, ListenerSelector, ListenerVolumeContext};
@@ -463,7 +463,7 @@ async fn local_listener_addresses_for_pod(
463463
obj: ObjectRef::<ListenerClass>::new(listener_class_name).erase(),
464464
})?;
465465

466-
Ok(node_primary_address(&node)
466+
Ok(node_primary_addresses(&node)
467467
.pick(listener_class.spec.preferred_address_type)
468468
.map(|(address, address_type)| ListenerIngress {
469469
// nodes: Some(vec![node_name.to_string()]),

rust/operator-binary/src/listener_controller.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use strum::IntoStaticStr;
3030

3131
use crate::{
3232
csi_server::node::NODE_TOPOLOGY_LABEL_HOSTNAME,
33-
utils::{node_primary_address, AddressCandidates},
33+
utils::address::{node_primary_addresses, AddressCandidates},
3434
};
3535

3636
#[cfg(doc)]
@@ -291,7 +291,7 @@ pub async fn reconcile(listener: Arc<Listener>, ctx: Arc<Ctx>) -> Result<control
291291
addresses = nodes
292292
.iter()
293293
.flat_map(|node| {
294-
node_primary_address(node).pick(listener_class.spec.preferred_address_type)
294+
node_primary_addresses(node).pick(listener_class.spec.preferred_address_type)
295295
})
296296
.collect::<Vec<_>>();
297297
ports = svc
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use stackable_operator::{commons::listener::AddressType, k8s_openapi::api::core::v1::Node};
2+
3+
/// The primary addresses of an entity, for each type of address.
4+
#[derive(Debug, Clone, Copy)]
5+
pub struct AddressCandidates<'a> {
6+
pub ip: Option<&'a str>,
7+
pub hostname: Option<&'a str>,
8+
}
9+
10+
impl<'a> AddressCandidates<'a> {
11+
/// Tries to pick the preferred [`AddressType`], falling back if it is not available.
12+
pub fn pick(&self, preferred_address_type: AddressType) -> Option<(&'a str, AddressType)> {
13+
let ip = self.ip.zip(Some(AddressType::Ip));
14+
let hostname = self.hostname.zip(Some(AddressType::Hostname));
15+
match preferred_address_type {
16+
AddressType::Ip => ip.or(hostname),
17+
AddressType::Hostname => hostname.or(ip),
18+
}
19+
}
20+
}
21+
22+
/// Try to guess the primary addresses of a Node, which it is expected that external clients should be able to reach it on
23+
pub fn node_primary_addresses(node: &Node) -> AddressCandidates {
24+
let addrs = node
25+
.status
26+
.as_ref()
27+
.and_then(|s| s.addresses.as_deref())
28+
.unwrap_or_default();
29+
30+
AddressCandidates {
31+
ip: addrs
32+
.iter()
33+
.find(|addr| addr.type_ == "ExternalIP")
34+
.or_else(|| addrs.iter().find(|addr| addr.type_ == "InternalIP"))
35+
.map(|addr| addr.address.as_str()),
36+
hostname: addrs
37+
.iter()
38+
.find(|addr| addr.type_ == "Hostname")
39+
.map(|addr| addr.address.as_str()),
40+
}
41+
}
42+
43+
#[cfg(test)]
44+
mod tests {
45+
use stackable_operator::{
46+
commons::listener::AddressType,
47+
k8s_openapi::api::core::v1::{Node, NodeAddress, NodeStatus},
48+
};
49+
50+
use super::node_primary_addresses;
51+
52+
#[test]
53+
fn node_with_only_ips_primary_address_returns_external_ip() {
54+
let node = node_from_addresses(vec![("InternalIP", "10.1.2.3"), ("ExternalIP", "1.2.3.4")]);
55+
let node_primary_address = node_primary_addresses(&node);
56+
assert_eq!(
57+
node_primary_address.pick(AddressType::Ip),
58+
Some(("1.2.3.4", AddressType::Ip))
59+
);
60+
assert_eq!(
61+
node_primary_address.pick(AddressType::Hostname),
62+
Some(("1.2.3.4", AddressType::Ip))
63+
);
64+
}
65+
66+
#[test]
67+
fn node_with_only_hostname_primary_address_returns_hostname() {
68+
let node = node_from_addresses(vec![
69+
("Hostname", "first-hostname"),
70+
("Hostname", "second-hostname"),
71+
]);
72+
let node_primary_address = node_primary_addresses(&node);
73+
assert_eq!(
74+
node_primary_address.pick(AddressType::Ip),
75+
Some(("first-hostname", AddressType::Hostname))
76+
);
77+
assert_eq!(
78+
node_primary_address.pick(AddressType::Hostname),
79+
Some(("first-hostname", AddressType::Hostname))
80+
);
81+
}
82+
83+
#[test]
84+
fn node_with_hostname_and_ips_primary_address() {
85+
let node = node_from_addresses(vec![
86+
("Hostname", "node-0"),
87+
("ExternalIP", "1.2.3.4"),
88+
("InternalIP", "10.1.2.3"),
89+
]);
90+
let node_primary_address = node_primary_addresses(&node);
91+
assert_eq!(
92+
node_primary_address.pick(AddressType::Ip),
93+
Some(("1.2.3.4", AddressType::Ip))
94+
);
95+
assert_eq!(
96+
node_primary_address.pick(AddressType::Hostname),
97+
Some(("node-0", AddressType::Hostname))
98+
);
99+
}
100+
101+
fn node_from_addresses<'a>(addresses: impl IntoIterator<Item = (&'a str, &'a str)>) -> Node {
102+
Node {
103+
status: Some(NodeStatus {
104+
addresses: Some(
105+
addresses
106+
.into_iter()
107+
.map(|(ty, addr)| NodeAddress {
108+
type_: ty.to_string(),
109+
address: addr.to_string(),
110+
})
111+
.collect(),
112+
),
113+
..Default::default()
114+
}),
115+
..Default::default()
116+
}
117+
}
118+
}

rust/operator-binary/src/utils.rs renamed to rust/operator-binary/src/utils/mod.rs

Lines changed: 3 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ use std::{os::unix::prelude::AsRawFd, path::Path};
22

33
use pin_project::pin_project;
44
use socket2::Socket;
5-
use stackable_operator::{commons::listener::AddressType, k8s_openapi::api::core::v1::Node};
65
use tokio::{
76
io::{AsyncRead, AsyncWrite},
87
net::{UnixListener, UnixStream},
98
};
109
use tonic::transport::server::Connected;
1110

11+
pub mod address;
12+
1213
/// Adapter for using [`UnixStream`] as a [`tonic`] connection
1314
/// Tonic usually communicates via TCP sockets, but the Kubernetes CSI interface expects
1415
/// plugins to use Unix sockets instead.
@@ -101,52 +102,9 @@ pub fn error_full_message(err: &dyn std::error::Error) -> String {
101102
full_msg
102103
}
103104

104-
#[derive(Debug, Clone, Copy)]
105-
pub struct AddressCandidates<'a> {
106-
pub ip: Option<&'a str>,
107-
pub hostname: Option<&'a str>,
108-
}
109-
110-
impl<'a> AddressCandidates<'a> {
111-
pub fn pick(&self, preferred_address_type: AddressType) -> Option<(&'a str, AddressType)> {
112-
let ip = self.ip.zip(Some(AddressType::Ip));
113-
let hostname = self.hostname.zip(Some(AddressType::Hostname));
114-
match preferred_address_type {
115-
AddressType::Ip => ip.or(hostname),
116-
AddressType::Hostname => hostname.or(ip),
117-
}
118-
}
119-
}
120-
121-
/// Try to guess the primary address of a Node, which it is expected that external clients should be able to reach it on
122-
pub fn node_primary_address(node: &Node) -> AddressCandidates {
123-
let addrs = node
124-
.status
125-
.as_ref()
126-
.and_then(|s| s.addresses.as_deref())
127-
.unwrap_or_default();
128-
129-
AddressCandidates {
130-
ip: addrs
131-
.iter()
132-
.find(|addr| addr.type_ == "ExternalIP")
133-
.or_else(|| addrs.iter().find(|addr| addr.type_ == "InternalIP"))
134-
.map(|addr| addr.address.as_str()),
135-
hostname: addrs
136-
.iter()
137-
.find(|addr| addr.type_ == "Hostname")
138-
.map(|addr| addr.address.as_str()),
139-
}
140-
}
141-
142105
#[cfg(test)]
143106
mod tests {
144-
use stackable_operator::{
145-
commons::listener::AddressType,
146-
k8s_openapi::api::core::v1::{Node, NodeAddress, NodeStatus},
147-
};
148-
149-
use crate::utils::{error_full_message, node_primary_address};
107+
use crate::utils::error_full_message;
150108

151109
#[test]
152110
fn error_messages() {
@@ -164,71 +122,4 @@ mod tests {
164122
"leaf: middleware: root error"
165123
);
166124
}
167-
168-
#[test]
169-
fn node_with_only_ips_primary_address_returns_external_ip() {
170-
let node = node_from_addresses(vec![("InternalIP", "10.1.2.3"), ("ExternalIP", "1.2.3.4")]);
171-
let node_primary_address = node_primary_address(&node);
172-
assert_eq!(
173-
node_primary_address.pick(AddressType::Ip),
174-
Some(("1.2.3.4", AddressType::Ip))
175-
);
176-
assert_eq!(
177-
node_primary_address.pick(AddressType::Hostname),
178-
Some(("1.2.3.4", AddressType::Ip))
179-
);
180-
}
181-
182-
#[test]
183-
fn node_with_only_hostname_primary_address_returns_hostname() {
184-
let node = node_from_addresses(vec![
185-
("Hostname", "first-hostname"),
186-
("Hostname", "second-hostname"),
187-
]);
188-
let node_primary_address = node_primary_address(&node);
189-
assert_eq!(
190-
node_primary_address.pick(AddressType::Ip),
191-
Some(("first-hostname", AddressType::Hostname))
192-
);
193-
assert_eq!(
194-
node_primary_address.pick(AddressType::Hostname),
195-
Some(("first-hostname", AddressType::Hostname))
196-
);
197-
}
198-
199-
#[test]
200-
fn node_with_hostname_and_ips_primary_address() {
201-
let node = node_from_addresses(vec![
202-
("Hostname", "node-0"),
203-
("ExternalIP", "1.2.3.4"),
204-
("InternalIP", "10.1.2.3"),
205-
]);
206-
let node_primary_address = node_primary_address(&node);
207-
assert_eq!(
208-
node_primary_address.pick(AddressType::Ip),
209-
Some(("1.2.3.4", AddressType::Ip))
210-
);
211-
assert_eq!(
212-
node_primary_address.pick(AddressType::Hostname),
213-
Some(("node-0", AddressType::Hostname))
214-
);
215-
}
216-
217-
fn node_from_addresses<'a>(addresses: impl IntoIterator<Item = (&'a str, &'a str)>) -> Node {
218-
Node {
219-
status: Some(NodeStatus {
220-
addresses: Some(
221-
addresses
222-
.into_iter()
223-
.map(|(ty, addr)| NodeAddress {
224-
type_: ty.to_string(),
225-
address: addr.to_string(),
226-
})
227-
.collect(),
228-
),
229-
..Default::default()
230-
}),
231-
..Default::default()
232-
}
233-
}
234125
}

0 commit comments

Comments
 (0)