1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use std::fmt;

use ipnet::IpNet;
use thiserror::Error;

use super::*;

/// ClusterIPFamily defines the types of supported IP families.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
pub enum ClusterIpFamily {
    InvalidIpFamily,
    Ipv4IpFamily,
    Ipv6IpFamily,
    DualStackIpFamily,
}

impl Default for ClusterIpFamily {
    fn default() -> Self {
        Self::InvalidIpFamily
    }
}

impl ClusterIpFamily {
    pub fn to_str(&self) -> &'static str {
        match self {
            Self::InvalidIpFamily => "InvalidIPFamily",
            Self::Ipv4IpFamily => "IPv4IPFamily",
            Self::Ipv6IpFamily => "IPv6IPFamily",
            Self::DualStackIpFamily => "DualStackIPFamily",
        }
    }

    pub(crate) fn ip_family_for_cidr_strings(cidrs: &[String]) -> Result<Self, InvalidIpFamily> {
        let count = cidrs.len();
        if count > 2 {
            return Err(InvalidIpFamily::TooManyCidrs(count));
        }

        let families = cidrs
            .iter()
            .map(|text| text.parse())
            .collect::<Result<Vec<IpNet>, _>>()?
            .into();
        Ok(families)
    }
}

impl From<IpNet> for ClusterIpFamily {
    fn from(ipnet: IpNet) -> Self {
        match ipnet {
            IpNet::V4(_) => Self::Ipv4IpFamily,
            IpNet::V6(_) => Self::Ipv6IpFamily,
        }
    }
}

impl From<Vec<IpNet>> for ClusterIpFamily {
    fn from(nets: Vec<IpNet>) -> Self {
        let mut nets = nets.into_iter().map(Self::from);

        let first = nets.next();
        let second = nets.next();

        if let Some(first) = first {
            if let Some(second) = second {
                if first == second {
                    first
                } else {
                    Self::DualStackIpFamily
                }
            } else {
                first
            }
        } else {
            Self::Ipv4IpFamily
        }
    }
}

impl fmt::Display for ClusterIpFamily {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.to_str().fmt(f)
    }
}

#[derive(Debug, Error)]
pub enum InvalidIpFamily {
    #[error("Too many ({0}) CIDRs specified")]
    TooManyCidrs(usize),
    #[error("Could not parse CIDR: {0}")]
    InvalidCidr(#[from] ipnet::AddrParseError),
    #[error("Pods and Services IP Families mismatch")]
    IpFamilyMismatch,
}