1#[cfg(feature = "serde")]
20mod bool;
21
22mod netplan;
23pub use netplan::*;
24
25use std::collections::HashMap;
26
27#[cfg(feature = "serde")]
28use serde::{Deserialize, Serialize};
29
30#[cfg(feature = "derive_builder")]
31use derive_builder::Builder;
32
33#[derive(Default, Debug, Clone, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35#[cfg_attr(feature = "derive_builder", derive(Builder))]
36#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
37#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
38pub struct NetplanConfig {
39 pub network: NetworkConfig,
40}
41
42#[derive(Default, Debug, Clone, PartialEq, Eq)]
43#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
44#[cfg_attr(feature = "derive_builder", derive(Builder))]
45#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
46#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
47pub struct NetworkConfig {
48 pub version: u8,
49 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
50 pub renderer: Option<Renderer>,
51 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
52 pub ethernets: Option<HashMap<String, EthernetConfig>>,
53 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
54 pub modems: Option<HashMap<String, ModemConfig>>,
55 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
56 pub wifis: Option<HashMap<String, WifiConfig>>,
57 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
58 pub bonds: Option<HashMap<String, BondConfig>>,
59 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
60 pub bridges: Option<HashMap<String, BridgeConfig>>,
61 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
62 pub vlans: Option<HashMap<String, VlanConfig>>,
63 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
64 pub tunnels: Option<HashMap<String, TunnelConfig>>,
65 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
66 pub vrfs: Option<HashMap<String, VrfsConfig>>,
67 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
68 pub dummy_devices: Option<HashMap<String, DummyDeviceConfig>>,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq)]
81#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
82#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
83pub enum Renderer {
84 #[cfg_attr(feature = "serde", serde(rename = "networkd"))]
85 Networkd,
86 #[cfg_attr(feature = "serde", serde(rename = "NetworkManager"))]
87 NetworkManager,
88 #[cfg_attr(feature = "serde", serde(rename = "sriov"))]
89 Sriov,
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[cfg_attr(feature = "serde", serde(untagged))]
102#[cfg_attr(feature = "serde", serde(rename = "lowercase"))]
103#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
104pub enum UseDomains {
105 Boolean(
106 #[cfg_attr(
107 feature = "serde",
108 serde(deserialize_with = "crate::bool::string_or_bool")
109 )]
110 bool,
111 ),
112 Route,
113}
114
115#[cfg(test)]
116mod test {
117 use crate::NetplanConfig;
118
119 #[test]
120 fn yaml_booleans() {
121 let input = r#"
122 network:
123 version: 2
124 ethernets:
125 nics:
126 match:
127 name: ens*
128 dhcp4: on
129 dhcp6: N
130 "#;
131
132 let netplan_config: NetplanConfig = serde_yaml::from_str(&input).unwrap();
133 let ethernets = netplan_config.network.ethernets.unwrap();
134 let ethernet = ethernets.values().next().unwrap();
135
136 assert!(ethernet.common_all.is_some());
137
138 let common = ethernet.common_all.as_ref().unwrap();
139
140 assert_eq!(common.dhcp4, Some(true));
141 }
142}