netplan_types/
lib.rs

1//! netplan-types
2//!
3//! ## Motivation
4//! This crate attempts to map the entire netplan configuration into Rust structs and enums.
5//! The 'layout' is as close to what you'd write in your netplan YAML files.
6//!
7//! The intented use of this crate is to allow for easy editing of the network configuration via the netplan
8//! configuration files from a Rust program.
9//!
10//! Based on the documentation from netplan, which can be found [here](https://netplan.io/reference/)
11//! Please note that I do not check the docs often for updates, if anything is missing or incorrect in the future,
12//! please open an issue or a pull-request so the issue can be addressed.
13//!
14//! ## Features
15//! - `serde`: \[Default\] Add serde support
16//! - `derive_builder` Enable the derive_builder crate for an automatically generated builder pattern API
17//! - `schemars`: Enable the schemars crate for generating a JSON schema from the structs
18
19#[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/// Use the given networking backend for this definition. Currently supported are
70/// networkd and NetworkManager. This property can be specified globally
71/// in network:, for a device type (in e. g. ethernets:) or
72/// for a particular device definition. Default is networkd.
73///
74/// (Since 0.99) The renderer property has one additional acceptable value for vlan
75/// objects (i. e. defined in vlans:): sriov. If a vlan is defined with the
76/// sriov renderer for an SR-IOV Virtual Function interface, this causes netplan to
77/// set up a hardware VLAN filter for it. There can be only one defined per VF.
78#[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/// Takes a boolean, or the special value “route”. When true, the domain
91/// name received from the DHCP server will be used as DNS search domain
92/// over this link, similar to the effect of the Domains= setting. If set
93/// to “route”, the domain name received from the DHCP server will be
94/// used for routing DNS queries only, but not for searching, similar to
95/// the effect of the Domains= setting when the argument is prefixed with
96/// “~”.
97#[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}