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 wifis: Option<HashMap<String, WifiConfig>>,
55 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
56 pub bonds: Option<HashMap<String, BondConfig>>,
57 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
58 pub bridges: Option<HashMap<String, BridgeConfig>>,
59 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
60 pub vlans: Option<HashMap<String, VlanConfig>>,
61 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
62 pub tunnels: Option<HashMap<String, TunnelConfig>>,
63 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
64 pub vrfs: Option<HashMap<String, VrfsConfig>>,
65 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
66 pub dummy_devices: Option<HashMap<String, DummyDeviceConfig>>,
67}
68
69#[derive(Debug, Clone, PartialEq, Eq)]
79#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
80#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
81pub enum Renderer {
82 #[cfg_attr(feature = "serde", serde(rename = "networkd"))]
83 Networkd,
84 #[cfg_attr(feature = "serde", serde(rename = "NetworkManager"))]
85 NetworkManager,
86 #[cfg_attr(feature = "serde", serde(rename = "sriov"))]
87 Sriov,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq)]
98#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
99#[cfg_attr(feature = "serde", serde(untagged))]
100#[cfg_attr(feature = "serde", serde(rename = "lowercase"))]
101#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
102pub enum UseDomains {
103 Boolean(
104 #[cfg_attr(
105 feature = "serde",
106 serde(deserialize_with = "crate::bool::string_or_bool")
107 )]
108 bool,
109 ),
110 Route,
111}
112
113#[cfg(test)]
114mod test {
115 use crate::NetplanConfig;
116
117 #[test]
118 fn yaml_booleans() {
119 let input = r#"
120 network:
121 version: 2
122 ethernets:
123 nics:
124 match:
125 name: ens*
126 dhcp4: on
127 dhcp6: N
128 "#;
129
130 let netplan_config: NetplanConfig = serde_yaml::from_str(&input).unwrap();
131 let ethernets = netplan_config.network.ethernets.unwrap();
132 let ethernet = ethernets.values().next().unwrap();
133
134 assert!(ethernet.common_all.is_some());
135
136 let common = ethernet.common_all.as_ref().unwrap();
137
138 assert_eq!(common.dhcp4, Some(true));
139 }
140}